Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
3e9cb5c
return a single results object instead of always a list
splch Apr 18, 2025
382be84
Clarify comment regarding single-circuit job results
splch Apr 18, 2025
80e830f
Clarify return type in Sampler.run_sweep documentation
splch Apr 18, 2025
af66606
Clarify handling of single-circuit job results in Service.run method
splch Apr 18, 2025
0625bbc
Refactor type annotations in job and sampler modules for consistency
splch Apr 18, 2025
6364c30
Add assertion to ensure job results are iterable in Service.run method
splch Apr 18, 2025
84b10f1
Refactor import statements for improved organization in service.py
splch Apr 18, 2025
ad95fc5
Merge branch 'main' into scalar-or-list-results
splch Apr 21, 2025
809e2b6
Add test to verify Service.run unwraps single result list
splch Apr 21, 2025
899cb05
format service
splch Apr 21, 2025
96797b6
Merge branch 'main' into scalar-or-list-results
splch Apr 24, 2025
7624722
Add test for Service.run_batch to preserve input order of circuits
splch Apr 24, 2025
e76ec62
Reorder import statements in service_test.py to follow conventions
splch Apr 24, 2025
5474b73
Merge branch 'main' into scalar-or-list-results
splch May 2, 2025
eb3038c
Merge branch 'main' into scalar-or-list-results
splch Oct 9, 2025
33e18a1
Refactor type hints in job, sampler, and service modules for consiste…
splch Oct 9, 2025
392a4b5
Fix formatting inconsistencies in comments across job, sampler, and s…
splch Oct 9, 2025
604876f
Enhance documentation for job results and sampler methods in IonQ API…
splch Oct 9, 2025
72027cd
Clarify result shape in job results documentation for IonQ API
splch Oct 9, 2025
49506df
Merge branch 'main' into scalar-or-list-results
mhucka Oct 13, 2025
967602c
Merge branch 'main' into scalar-or-list-results
splch Oct 14, 2025
d4f5442
remove block quoting the note and use normal markdown
splch Oct 14, 2025
23ce8a9
Merge branch 'main' into scalar-or-list-results
splch Oct 15, 2025
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
28 changes: 20 additions & 8 deletions cirq-ionq/cirq_ionq/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import json
import time
import warnings
from typing import Dict, Optional, Sequence, TYPE_CHECKING, Union
from typing import Dict, Optional, Sequence, TYPE_CHECKING, Union, List

import cirq
from cirq._doc import document
Expand Down Expand Up @@ -195,7 +195,12 @@ def results(
polling_seconds: int = 1,
sharpen: Optional[bool] = None,
extra_query_params: Optional[dict] = None,
) -> Union[list[results.QPUResult], list[results.SimulatorResult]]:
) -> Union[
results.QPUResult,
results.SimulatorResult,
List[results.QPUResult],
List[results.SimulatorResult],
]:
"""Polls the IonQ api for results.

Args:
Expand Down Expand Up @@ -242,11 +247,10 @@ def results(
job_id=self.job_id(), sharpen=sharpen, extra_query_params=extra_query_params
)

# is this a batch run (dict‑of‑dicts) or a single circuit?
some_inner_value = next(iter(backend_results.values()))
if isinstance(some_inner_value, dict):
histograms = backend_results.values()
else:
histograms = [backend_results]
is_batch = isinstance(some_inner_value, dict)
histograms = list(backend_results.values()) if is_batch else [backend_results]

# IonQ returns results in little endian, but
# Cirq prefers to use big endian, so we convert.
Expand All @@ -267,7 +271,11 @@ def results(
measurement_dict=self.measurement_dict(circuit_index=circuit_index),
)
)
return big_endian_results_qpu
return (
big_endian_results_qpu
if len(big_endian_results_qpu) > 1
else big_endian_results_qpu[0]
)
else:
big_endian_results_sim: list[results.SimulatorResult] = []
for circuit_index, histogram in enumerate(histograms):
Expand All @@ -283,7 +291,11 @@ def results(
repetitions=self.repetitions(),
)
)
return big_endian_results_sim
return (
big_endian_results_sim
if len(big_endian_results_sim) > 1
else big_endian_results_sim[0]
)

def cancel(self):
"""Cancel the given job.
Expand Down
22 changes: 11 additions & 11 deletions cirq-ionq/cirq_ionq/job_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def test_job_results_qpu():
assert "foo" in str(w[0].message)
assert "bar" in str(w[1].message)
expected = ionq.QPUResult({0: 600, 1: 400}, 2, {'a': [0, 1]})
assert results[0] == expected
assert results == expected


def test_batch_job_results_qpu():
Expand Down Expand Up @@ -146,7 +146,7 @@ def test_job_results_rounding_qpu():
job = ionq.Job(mock_client, job_dict)
expected = ionq.QPUResult({0: 3, 1: 4997}, 2, {'a': [0, 1]})
results = job.results()
assert results[0] == expected
assert results == expected


def test_job_results_failed():
Expand Down Expand Up @@ -177,7 +177,7 @@ def test_job_results_qpu_endianness():
}
job = ionq.Job(mock_client, job_dict)
results = job.results()
assert results[0] == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={})
assert results == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={})


def test_batch_job_results_qpu_endianness():
Expand All @@ -198,7 +198,7 @@ def test_batch_job_results_qpu_endianness():
}
job = ionq.Job(mock_client, job_dict)
results = job.results()
assert results[0] == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={'a': [0, 1]})
assert results == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={'a': [0, 1]})


def test_job_results_qpu_target_endianness():
Expand All @@ -214,7 +214,7 @@ def test_job_results_qpu_target_endianness():
}
job = ionq.Job(mock_client, job_dict)
results = job.results()
assert results[0] == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={})
assert results == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={})


def test_batch_job_results_qpu_target_endianness():
Expand All @@ -236,7 +236,7 @@ def test_batch_job_results_qpu_target_endianness():
}
job = ionq.Job(mock_client, job_dict)
results = job.results()
assert results[0] == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={'a': [0, 1]})
assert results == ionq.QPUResult({0: 600, 2: 400}, 2, measurement_dict={'a': [0, 1]})


@mock.patch('time.sleep', return_value=None)
Expand All @@ -254,7 +254,7 @@ def test_job_results_poll(mock_sleep):
mock_client.get_results.return_value = {'0': '0.6', '1': '0.4'}
job = ionq.Job(mock_client, ready_job)
results = job.results(polling_seconds=0)
assert results[0] == ionq.QPUResult({0: 600, 1: 400}, 1, measurement_dict={})
assert results == ionq.QPUResult({0: 600, 1: 400}, 1, measurement_dict={})
mock_sleep.assert_called_once()


Expand Down Expand Up @@ -292,7 +292,7 @@ def test_job_results_simulator():
}
job = ionq.Job(mock_client, job_dict)
results = job.results()
assert results[0] == ionq.SimulatorResult({0: 0.6, 1: 0.4}, 1, {}, 100)
assert results == ionq.SimulatorResult({0: 0.6, 1: 0.4}, 1, {}, 100)


def test_batch_job_results_simulator():
Expand Down Expand Up @@ -334,7 +334,7 @@ def test_job_results_simulator_endianness():
}
job = ionq.Job(mock_client, job_dict)
results = job.results()
assert results[0] == ionq.SimulatorResult({0: 0.6, 2: 0.4}, 2, {}, 100)
assert results == ionq.SimulatorResult({0: 0.6, 2: 0.4}, 2, {}, 100)


def test_batch_job_results_simulator_endianness():
Expand All @@ -355,7 +355,7 @@ def test_batch_job_results_simulator_endianness():
}
job = ionq.Job(mock_client, job_dict)
results = job.results()
assert results[0] == ionq.SimulatorResult({0: 0.6, 2: 0.4}, 2, {'a': [0, 1]}, 1000)
assert results == ionq.SimulatorResult({0: 0.6, 2: 0.4}, 2, {'a': [0, 1]}, 1000)


def test_job_sharpen_results():
Expand All @@ -370,7 +370,7 @@ def test_job_sharpen_results():
}
job = ionq.Job(mock_client, job_dict)
results = job.results(sharpen=False)
assert results[0] == ionq.SimulatorResult({0: 60, 1: 40}, 1, {}, 100)
assert results == ionq.SimulatorResult({0: 60, 1: 40}, 1, {}, 100)


def test_job_cancel():
Expand Down
11 changes: 8 additions & 3 deletions cirq-ionq/cirq_ionq/sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,16 @@ def run_sweep(
)
for resolver in resolvers
]
# ─── collect results ───────────────────────────────────────────
if self._timeout_seconds is not None:
job_results = [job.results(timeout_seconds=self._timeout_seconds) for job in jobs]
raw_results = [j.results(timeout_seconds=self._timeout_seconds) for j in jobs]
else:
job_results = [job.results() for job in jobs]
flattened_job_results = list(itertools.chain.from_iterable(job_results))
raw_results = [j.results() for j in jobs]

# each element of `raw_results` might be a single result or a list
flattened_job_results = []
for r in raw_results:
flattened_job_results.extend(r if isinstance(r, list) else [r])
cirq_results = []
for result, params in zip(flattened_job_results, resolvers):
if isinstance(result, results.QPUResult):
Expand Down
19 changes: 11 additions & 8 deletions cirq-ionq/cirq_ionq/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,21 +124,24 @@ def run(
A `cirq.Result` for running the circuit.
"""
resolved_circuit = cirq.resolve_parameters(circuit, param_resolver)
job_results = self.create_job(
job_out = self.create_job(
circuit=resolved_circuit,
repetitions=repetitions,
name=name,
target=target,
error_mitigation=error_mitigation,
extra_query_params=extra_query_params,
).results(sharpen=sharpen)
if isinstance(job_results[0], results.QPUResult):
return job_results[0].to_cirq_result(params=cirq.ParamResolver(param_resolver))
if isinstance(job_results[0], results.SimulatorResult):
return job_results[0].to_cirq_result(
params=cirq.ParamResolver(param_resolver), seed=seed
)
raise NotImplementedError(f"Unrecognized job result type '{type(job_results[0])}'.")

# normalise: single‑circuit jobs should deliver one result
if isinstance(job_out, list):
job_out = job_out[0]

if isinstance(job_out, results.QPUResult):
return job_out.to_cirq_result(params=cirq.ParamResolver(param_resolver))
if isinstance(job_out, results.SimulatorResult):
return job_out.to_cirq_result(params=cirq.ParamResolver(param_resolver), seed=seed)
raise NotImplementedError(f"Unrecognized job result type '{type(job_out)}'.")

def run_batch(
self,
Expand Down
Loading