Skip to content

Commit

Permalink
Merge https://github.com/iqm-finland/cirq-on-iqm into comp-1368-naive…
Browse files Browse the repository at this point in the history
…-move-gate-support
  • Loading branch information
Arianne Meijer committed Aug 28, 2024
2 parents b3488b9 + 572edf4 commit 6f71d2f
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 52 deletions.
11 changes: 9 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@
Changelog
=========

Version 14.2
Version 14.3
============

* Improved operation validation to check if it is calibrated according to the metadata rather than assuming. `#133 <https://github.com/iqm-finland/cirq-on-iqm/pull/133>`_
* Added IQMMoveGate class for Deneb architectures. `#133 <https://github.com/iqm-finland/cirq-on-iqm/pull/133>`_
* Updated IQMDevice class to support devices with resonators. `#133 <https://github.com/iqm-finland/cirq-on-iqm/pull/133>`_
* Require iqm-client >= 17.8. `#133 <https://github.com/iqm-finland/cirq-on-iqm/pull/133>`_
* Support for :class:`CircuitCompilationOptions` from ``iqm-client`` when submitting a circuit to an IQM device.
* Require iqm-client >= 18.0. `#133 <https://github.com/iqm-finland/cirq-on-iqm/pull/133>`_

Version 14.2
============

* Allow inspecting a run request before submitting it for execution. `#134 <https://github.com/iqm-finland/cirq-on-iqm/pull/134>`_
* Require iqm-client >= 17.8. `#134 <https://github.com/iqm-finland/cirq-on-iqm/pull/134>`_

Version 14.1
============
Expand Down
24 changes: 24 additions & 0 deletions docs/user_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,30 @@ This is often faster than executing the circuits individually. Circuits submitte
print(result.histogram(key="m"))
Inspecting the final circuits before submitting them for execution
------------------------------------------------------------------

It is possible to inspect the final circuits that would be submitted for execution before actually submitting them,
which can be useful for debugging purposes. This can be done using :meth:`.IQMSampler.create_run_request`, which returns
a :class:`~iqm.iqm_client.models.RunRequest` containing the circuits and other data. The method accepts the same
parameters as :meth:`.IQMSampler.run` and :meth:`.IQMSampler.run_iqm_batch`, and creates the run request in the same
way as those functions.

.. code-block:: python
# inspect the run_request without submitting it for execution
run_request = sampler.create_run_request(routed_circuit_1, repetitions=10)
print(run_request)
# the following calls submit exactly the same run request for execution on the server
sampler.run(routed_circuit_1, repetitions=10)
sampler._client.submit_run_request(run_request)
It is also possible to print a run request when it is actually submitted by setting the environment variable
``IQM_CLIENT_DEBUG=1``.


More examples
-------------

Expand Down
67 changes: 46 additions & 21 deletions src/iqm/cirq_iqm/iqm_sampler.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,7 @@ def close_client(self):
def run_sweep( # type: ignore[override]
self, program: cirq.Circuit, params: cirq.Sweepable, repetitions: int = 1
) -> list[IQMResult]:
# validate the circuit for the device
self._device.validate_circuit(program)

resolvers = list(cirq.to_resolvers(params))

circuits = [cirq.protocols.resolve_parameters(program, res) for res in resolvers] if resolvers else [program]

circuits, resolvers = self._resolve_parameters(program, params)
results, metadata = self._send_circuits(
circuits,
repetitions=repetitions,
Expand Down Expand Up @@ -124,16 +118,40 @@ def run_iqm_batch(self, programs: list[cirq.Circuit], repetitions: int = 1) -> l
APITimeoutError: server did not return the results in the allocated time
RuntimeError: IQM client session has been closed
"""
# validate each circuit for the device
for program in programs:
self._device.validate_circuit(program)

results, metadata = self._send_circuits(
programs,
repetitions=repetitions,
)
return [IQMResult(measurements=result, metadata=metadata) for result in results]

def create_run_request(
self, programs: cirq.Circuit | list[cirq.Circuit], *, params: cirq.Sweepable = None, repetitions: int = 1
) -> RunRequest:
"""Creates a run request without submitting it for execution.
This takes the same parameters as :meth:`run` and :meth:`run_iqm_batch`, and can be used to check the
run request that would be sent when calling those functions.
Args:
programs: quantum circuit(s) that would be executed when submitting the run request
params: same as ``params`` for :meth:`run`, used only if ``programs`` is not a list
repetitions: number of times the circuits are sampled
Returns:
the created run request
"""
if isinstance(programs, cirq.Circuit):
programs, _ = self._resolve_parameters(programs, params)

serialized_circuits = self._validate_and_serialize_circuits(programs)

return self._client.create_run_request(
serialized_circuits,
calibration_set_id=self._calibration_set_id,
shots=repetitions,
options=self._compiler_options,
)

def _send_circuits(
self,
circuits: list[cirq.Circuit],
Expand All @@ -149,17 +167,9 @@ def _send_circuits(
Returns:
circuit execution results, result metadata
"""
run_request = self.create_run_request(circuits, repetitions=repetitions)
job_id = self._client.submit_run_request(run_request)

if not self._client:
raise RuntimeError('Cannot submit circuits since session to IQM client has been closed.')
serialized_circuits = [serialize_circuit(circuit) for circuit in circuits]

job_id = self._client.submit_circuits(
serialized_circuits,
calibration_set_id=self._calibration_set_id,
shots=repetitions,
options=self._compiler_options,
)
timeout_arg = [self._run_sweep_timeout] if self._run_sweep_timeout is not None else []

try:
Expand All @@ -181,6 +191,21 @@ def _send_circuits(
ResultMetadata(job_id, results.metadata.calibration_set_id, results.metadata.request),
)

@staticmethod
def _resolve_parameters(
program: cirq.Circuit, params: cirq.Sweepable
) -> tuple[list[cirq.Circuit], list[cirq.ParamResolver]]:
resolvers = list(cirq.to_resolvers(params))
circuits = [cirq.protocols.resolve_parameters(program, res) for res in resolvers] if resolvers else [program]
return circuits, resolvers

def _validate_and_serialize_circuits(self, circuits: list[cirq.Circuit]) -> list[Circuit]:
if not self._client:
raise RuntimeError('Cannot submit circuits since session to IQM client has been closed.')
for circuit in circuits:
self._device.validate_circuit(circuit)
return [serialize_circuit(circuit) for circuit in circuits]


@dataclass
class ResultMetadata:
Expand Down
Loading

0 comments on commit 6f71d2f

Please sign in to comment.