From c4b267017025cc870f409422c3b80a6c7bd0ace9 Mon Sep 17 00:00:00 2001 From: Valentin Macheret Date: Thu, 30 Oct 2025 18:36:13 +0100 Subject: [PATCH 1/5] feat(qio): update to qio --- qiskit_scaleway/backends/aqt/backend.py | 1 - qiskit_scaleway/backends/base_job.py | 155 ++++++++---------------- requirements.txt | 3 +- 3 files changed, 53 insertions(+), 106 deletions(-) diff --git a/qiskit_scaleway/backends/aqt/backend.py b/qiskit_scaleway/backends/aqt/backend.py index 3725575..7727568 100644 --- a/qiskit_scaleway/backends/aqt/backend.py +++ b/qiskit_scaleway/backends/aqt/backend.py @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - from qiskit.providers import Options from qiskit_scaleway.backends import BaseBackend diff --git a/qiskit_scaleway/backends/base_job.py b/qiskit_scaleway/backends/base_job.py index 1391ffd..9872b7a 100644 --- a/qiskit_scaleway/backends/base_job.py +++ b/qiskit_scaleway/backends/base_job.py @@ -1,4 +1,4 @@ -# Copyright 2024 Scaleway +# Copyright 2025 Scaleway # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,32 +12,31 @@ # See the License for the specific language governing permissions and # limitations under the License. import time -import zlib import httpx -import json -import numpy as np import randomname from typing import List, Union, Optional, Dict -from qiskit import qasm3, QuantumCircuit +from qiskit import QuantumCircuit from qiskit.result import Result from qiskit.providers import JobV1 from qiskit.providers import JobError, JobTimeoutError, JobStatus from qiskit_scaleway.versions import USER_AGENT +from qio.core import ( + QuantumProgram, + QuantumProgramResult, + QuantumComputationModel, + QuantumComputationParameters, + QuantumNoiseModel, + BackendData, + ClientData, +) + from scaleway_qaas_client.v1alpha1 import ( QaaSClient, QaaSJobResult, - QaaSJobData, - QaaSJobClientData, - QaaSCircuitData, - QaaSJobRunData, - QaaSJobBackendData, - QaaSCircuitSerializationFormat, - QaaSNoiseModelData, - QaaSNoiseModelSerializationFormat, ) @@ -78,59 +77,39 @@ def submit(self, session_id: str) -> None: options = self._config.copy() shots = options.pop("shots") - run_data = QaaSJobRunData( - options={ - "shots": shots, - "memory": options.pop("memory", False), - }, - circuits=list( - map( - lambda c: QaaSCircuitData( - serialization_format=QaaSCircuitSerializationFormat.QASM_V3, - circuit_serialization=qasm3.dumps(c), - ), - self._circuits, - ) - ), - ) + programs = map(lambda c: QuantumProgram.from_qiskit_circuit(c), self._circuits) noise_model = options.pop("noise_model", None) if noise_model: - noise_model_dict = _encode_numpy_complex(noise_model.to_dict(False)) - noise_model = QaaSNoiseModelData( - serialization_format=QaaSNoiseModelSerializationFormat.AER_COMPRESSED_JSON, - noise_model_serialization=zlib.compress( - json.dumps(noise_model_dict).encode() - ), - ) - ### Uncomment to use standard JSON serialization, provided there is no more issue with AER deserialization logic - # noise_model = QaaSNoiseModelData( - # serialization_format = QaaSNoiseModelSerializationFormat.JSON, - # noise_model_serialization = json.dumps(noise_model.to_dict(True)).encode() - # ) - ### - - backend_data = QaaSJobBackendData( + noise_model = QuantumNoiseModel.from_qiskit_aer_noise_model(noise_model) + + backend_data = BackendData( name=self.backend().name, version=self.backend().version, options=options, + frozenset=True, ) - client_data = QaaSJobClientData( + client_data = ClientData( user_agent=USER_AGENT, + frozenset=True, ) - data = QaaSJobData.schema().dumps( - QaaSJobData( - backend=backend_data, - run=run_data, - client=client_data, - noise_model=noise_model, - ) - ) + computation_model_dict = QuantumComputationModel( + programs=programs, + backend=backend_data, + client=client_data, + noise_model=noise_model, + frozenset=True, + ).to_dict() + + computation_parameters_dict = QuantumComputationParameters( + shots=shots, + frozenset=True, + ).to_dict() model = self._client.create_model( - payload=data, + payload=computation_model_dict, ) if not model: @@ -140,7 +119,7 @@ def submit(self, session_id: str) -> None: name=self._name, session_id=session_id, model_id=model.id, - parameters={"shots": shots}, + parameters=computation_parameters_dict, ).id def result( @@ -151,37 +130,28 @@ def result( job_results = self._wait_for_result(timeout, fetch_interval) - def __make_result_from_payload(payload: str) -> Result: - payload_dict = json.loads(payload) - - return Result.from_dict( - { - "results": payload_dict["results"], - "backend_name": self.backend().name, - "backend_version": self.backend().version, - "job_id": self._job_id, - "qobj_id": ", ".join(x.name for x in self._circuits), - "success": payload_dict["success"], - "header": payload_dict.get("header"), - "metadata": payload_dict.get("metadata"), - } - ) - - qiskit_results = list( + program_results = list( map( - lambda r: __make_result_from_payload( - self._extract_payload_from_response(r) + lambda r: self._extract_payload_from_response(r).to_qiskit_result( + **{ + "backend_name": self.backend().name, + "backend_version": self.backend().version, + "job_id": self._job_id, + "qobj_id": ", ".join(x.name for x in self._circuits), + } ), job_results, ) ) - if len(qiskit_results) == 1: - return qiskit_results[0] + if len(program_results) == 1: + return program_results[0] - return qiskit_results + return program_results - def _extract_payload_from_response(self, job_result: QaaSJobResult) -> str: + def _extract_payload_from_response( + self, job_result: QaaSJobResult + ) -> QuantumProgramResult: result = job_result.result if result is None or result == "": @@ -190,12 +160,11 @@ def _extract_payload_from_response(self, job_result: QaaSJobResult) -> str: if url is not None: resp = httpx.get(url) resp.raise_for_status() - - return resp.text + result = resp.text else: - raise Exception("Got result with empty data and url fields") - else: - return result + raise RuntimeError("Got result with empty data and url fields") + + return QuantumProgramResult.from_json(result) def _wait_for_result( self, timeout: Optional[int], fetch_interval: int @@ -217,25 +186,3 @@ def _wait_for_result( raise JobError("Job error") time.sleep(fetch_interval) - - -def _encode_numpy_complex(obj): - """ - Recursively traverses a structure and converts numpy arrays and - complex numbers into a JSON-serializable format. - """ - if isinstance(obj, np.ndarray): - return { - "__ndarray__": True, - "data": _encode_numpy_complex(obj.tolist()), # Recursively encode data - "dtype": obj.dtype.name, - "shape": obj.shape, - } - elif isinstance(obj, (complex, np.complex128)): - return {"__complex__": True, "real": obj.real, "imag": obj.imag} - elif isinstance(obj, dict): - return {key: _encode_numpy_complex(value) for key, value in obj.items()} - elif isinstance(obj, (list, tuple)): - return [_encode_numpy_complex(item) for item in obj] - else: - return obj diff --git a/requirements.txt b/requirements.txt index 2abc369..bfccbd6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ qiskit-aer~=0.17 randomname>=0.2.1 dataclasses-json>=0.6.4 dataclasses>=0.6 -scaleway-qaas-client>=0.1.23 \ No newline at end of file +scaleway-qaas-client>=0.1.23 +qio>=0.1.0 \ No newline at end of file From 78842c66b23b81b33fd916ba8ed8f9fced1537c5 Mon Sep 17 00:00:00 2001 From: Valentin Macheret Date: Mon, 3 Nov 2025 12:52:26 +0100 Subject: [PATCH 2/5] feat(qio): update to qio --- qiskit_scaleway/backends/qsim/job.py | 289 +++++---------------------- 1 file changed, 51 insertions(+), 238 deletions(-) diff --git a/qiskit_scaleway/backends/qsim/job.py b/qiskit_scaleway/backends/qsim/job.py index 056ef9c..0bd9516 100644 --- a/qiskit_scaleway/backends/qsim/job.py +++ b/qiskit_scaleway/backends/qsim/job.py @@ -11,85 +11,31 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import json -import io -import collections - -import numpy as np - from typing import ( - Any, List, - Callable, - Iterable, - Mapping, - Optional, - Sequence, - Tuple, Union, - cast, Dict, ) -from qiskit import qasm2, QuantumCircuit +from qiskit import QuantumCircuit from qiskit.providers import JobError, JobStatus from qiskit.result import Result from qiskit.transpiler.passes import RemoveBarriers -from qiskit.result.models import ExperimentResult, ExperimentResultData from qiskit_scaleway.versions import USER_AGENT from qiskit_scaleway.backends import BaseJob -from scaleway_qaas_client.v1alpha1 import ( - QaaSClient, - QaaSJobData, - QaaSJobClientData, - QaaSCircuitData, - QaaSJobRunData, - QaaSJobBackendData, - QaaSCircuitSerializationFormat, +from qio.core import ( + QuantumProgram, + QuantumProgramSerializationFormat, + QuantumProgramResult, + QuantumComputationModel, + QuantumComputationParameters, + BackendData, + ClientData, ) - -def _tuple_of_big_endian_int(bit_groups: Iterable[Any]) -> Tuple[int, ...]: - return tuple(_big_endian_bits_to_int(bits) for bits in bit_groups) - - -def _big_endian_bits_to_int(bits: Iterable[Any]) -> int: - result = 0 - - for e in bits: - result <<= 1 - if e: - result |= 1 - - return result - - -def _unpack_digits( - packed_digits: str, - binary: bool, - dtype: Optional[str], - shape: Optional[Sequence[int]], -) -> np.ndarray: - if binary: - dtype = cast(str, dtype) - shape = cast(Sequence[int], shape) - return _unpack_bits(packed_digits, dtype, shape) - - buffer = io.BytesIO() - buffer.write(bytes.fromhex(packed_digits)) - buffer.seek(0) - digits = np.load(buffer, allow_pickle=False) - buffer.close() - - return digits - - -def _unpack_bits(packed_bits: str, dtype: str, shape: Sequence[int]) -> np.ndarray: - bits_bytes = bytes.fromhex(packed_bits) - bits = np.unpackbits(np.frombuffer(bits_bytes, dtype=np.uint8)) - return bits[: np.prod(shape).item()].reshape(shape).astype(dtype) +from scaleway_qaas_client.v1alpha1 import QaaSClient class QsimJob(BaseJob): @@ -116,118 +62,69 @@ def submit(self, session_id: str) -> None: # Note 2: Qsim can only handle one circuit at a time circuit = RemoveBarriers()(self._circuits[0]) - run_data = QaaSJobRunData( - options={"shots": options.pop("shots")}, - circuits=[ - QaaSCircuitData( - serialization_format=QaaSCircuitSerializationFormat.QASM_V2, - circuit_serialization=qasm2.dumps(circuit), - ) - ], - ) + programs = [ + QuantumProgram.from_qiskit_circuit( + circuit, QuantumProgramSerializationFormat.QASM_V2 + ) + ] options.pop("circuit_memoization_size") - backend_data = QaaSJobBackendData( + backend_data = BackendData( name=self.backend().name, version=self.backend().version, options=options, + frozenset=True, ) - client_data = QaaSJobClientData( + client_data = ClientData( user_agent=USER_AGENT, + frozenset=True, ) - data = QaaSJobData.schema().dumps( - QaaSJobData( - backend=backend_data, - run=run_data, - client=client_data, - ) - ) + computation_model_dict = QuantumComputationModel( + programs=programs, + backend=backend_data, + client=client_data, + frozenset=True, + ).to_dict() + + computation_parameters_dict = QuantumComputationParameters( + shots=options.pop("shots"), + frozenset=True, + ).to_dict() model = self._client.create_model( - payload=data, + payload=computation_model_dict, ) if not model: raise RuntimeError("Failed to push circuit data") self._job_id = self._client.create_job( - name=self._name, session_id=session_id, model_id=model.id + name=self._name, + session_id=session_id, + model_id=model.id, + parameters=computation_parameters_dict, ).id - def __to_cirq_result(self, job_results) -> "cirq.Result": + def __to_cirq_result(self, program_result: QuantumProgramResult) -> "cirq.Result": try: import cirq except: raise Exception("Cannot get Cirq result: Cirq not installed") - from cirq.study import ResultDict - - if len(job_results) == 0: - raise Exception("Empty result list") - - payload = self._extract_payload_from_response(job_results[0]) - payload_dict = json.loads(payload) - cirq_result = ResultDict._from_json_dict_(**payload_dict) - - return cirq_result - - def __to_qiskit_result(self, job_results): - def __make_hex_from_result_array(result: Tuple): - str_value = "".join(map(str, result)) - integer_value = int(str_value, 2) - return hex(integer_value) - - def __make_expresult_from_cirq_result( - cirq_result: CirqResult, - ) -> ExperimentResult: - hist = dict( - cirq_result.multi_measurement_histogram( - keys=cirq_result.measurements.keys() - ) - ) - - return ExperimentResult( - shots=cirq_result.repetitions, - success=True, - data=ExperimentResultData( - counts={ - __make_hex_from_result_array(key): value - for key, value in hist.items() - }, - ), - ) - - def __make_result_from_payload(payload: str) -> Result: - payload_dict = json.loads(payload) - cirq_result = CirqResult._from_json_dict_(**payload_dict) + return program_result.to_cirq_result() - return Result( - backend_name=self.backend().name, - backend_version=self.backend().version, - job_id=self._job_id, - qobj_id=", ".join(x.name for x in self._circuits), - success=self.status() == JobStatus.DONE, - results=[__make_expresult_from_cirq_result(cirq_result)], - cirq_result=payload, - ) - - qiskit_results = list( - map( - lambda r: __make_result_from_payload( - self._extract_payload_from_response(r) - ), - job_results, - ) + def __to_qiskit_result(self, program_result: QuantumProgramResult) -> Result: + return program_result.to_qiskit_result( + backend_name=self.backend().name, + backend_version=self.backend().version, + job_id=self._job_id, + qobj_id=", ".join(x.name for x in self._circuits), + success=self.status() == JobStatus.DONE, ) - if len(qiskit_results) == 1: - return qiskit_results[0] - - return qiskit_results - def result( self, timeout=None, @@ -244,97 +141,13 @@ def result( job_results = self._wait_for_result(timeout, fetch_interval) - return match.get(format, self.__to_qiskit_result)(job_results) - - -class CirqResult: - def __init__( - self, - *, - measurements: Optional[Mapping[str, np.ndarray]] = None, - records: Optional[Mapping[str, np.ndarray]] = None, - ) -> None: - if measurements is None and records is None: - measurements = {} - records = {} - self._params = None - self._measurements = measurements - self._records = records - - @property - def measurements(self) -> Mapping[str, np.ndarray]: - if self._measurements is None: - assert self._records is not None - self._measurements = {} - for key, data in self._records.items(): - reps, instances, qubits = data.shape - if instances != 1: - raise ValueError("Cannot extract 2D measurements for repeated keys") - self._measurements[key] = data.reshape((reps, qubits)) - return self._measurements + conv_method = match.get(format, self.__to_qiskit_result) - @property - def records(self) -> Mapping[str, np.ndarray]: - if self._records is None: - assert self._measurements is not None - self._records = { - key: data[:, np.newaxis, :] for key, data in self._measurements.items() - } - return self._records - - @property - def repetitions(self) -> int: - if self._records is not None: - if not self._records: - return 0 - return len(next(iter(self._records.values()))) - else: - if not self._measurements: - return 0 - return len(next(iter(self._measurements.values()))) - - def multi_measurement_histogram( - self, - *, - keys: Iterable, - fold_func: Callable = cast(Callable, _tuple_of_big_endian_int), - ) -> collections.Counter: - fixed_keys = tuple(key for key in keys) - samples: Iterable[Any] = zip( - *(self.measurements[sub_key] for sub_key in fixed_keys) - ) - - if len(fixed_keys) == 0: - samples = [()] * self.repetitions - - c: collections.Counter = collections.Counter() - - for sample in samples: - c[fold_func(sample)] += 1 - return c - - @classmethod - def _from_packed_records(cls, records, **kwargs): - return cls( - records={key: _unpack_digits(**val) for key, val in records.items()}, - **kwargs, - ) - - @classmethod - def _from_json_dict_(cls, **kwargs): - if "measurements" in kwargs: - measurements = kwargs["measurements"] - return cls( - params=None, - measurements={ - key: _unpack_digits(**val) for key, val in measurements.items() - }, + results = list( + map( + lambda r: conv_method(self._extract_payload_from_response(r)), + job_results, ) - return cls._from_packed_records(records=kwargs["records"]) + ) - @property - def repetitions(self) -> int: - if not self.records: - return 0 - # Get the length quickly from one of the keyed results. - return len(next(iter(self.records.values()))) + return results From b18789b93a70c7b3ddc452899f183ad3dfaa6223 Mon Sep 17 00:00:00 2001 From: Valentin Macheret Date: Mon, 3 Nov 2025 18:06:43 +0100 Subject: [PATCH 3/5] feat(qio): fix dict update --- qiskit_scaleway/backends/base_job.py | 28 +++++++++++----------------- qiskit_scaleway/backends/qsim/job.py | 23 +++++++++++------------ 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/qiskit_scaleway/backends/base_job.py b/qiskit_scaleway/backends/base_job.py index 9872b7a..6d1a5c1 100644 --- a/qiskit_scaleway/backends/base_job.py +++ b/qiskit_scaleway/backends/base_job.py @@ -87,29 +87,25 @@ def submit(self, session_id: str) -> None: name=self.backend().name, version=self.backend().version, options=options, - frozenset=True, ) client_data = ClientData( user_agent=USER_AGENT, - frozenset=True, ) - computation_model_dict = QuantumComputationModel( + computation_model_json = QuantumComputationModel( programs=programs, backend=backend_data, client=client_data, noise_model=noise_model, - frozenset=True, - ).to_dict() + ).to_json_str() - computation_parameters_dict = QuantumComputationParameters( + computation_parameters_json = QuantumComputationParameters( shots=shots, - frozenset=True, - ).to_dict() + ).to_json_str() model = self._client.create_model( - payload=computation_model_dict, + payload=computation_model_json, ) if not model: @@ -119,7 +115,7 @@ def submit(self, session_id: str) -> None: name=self._name, session_id=session_id, model_id=model.id, - parameters=computation_parameters_dict, + parameters=computation_parameters_json, ).id def result( @@ -133,12 +129,10 @@ def result( program_results = list( map( lambda r: self._extract_payload_from_response(r).to_qiskit_result( - **{ - "backend_name": self.backend().name, - "backend_version": self.backend().version, - "job_id": self._job_id, - "qobj_id": ", ".join(x.name for x in self._circuits), - } + backend_name=self.backend().name, + backend_version=self.backend().version, + job_id=self._job_id, + qobj_id=", ".join(x.name for x in self._circuits), ), job_results, ) @@ -164,7 +158,7 @@ def _extract_payload_from_response( else: raise RuntimeError("Got result with empty data and url fields") - return QuantumProgramResult.from_json(result) + return QuantumProgramResult.from_json_str(result) def _wait_for_result( self, timeout: Optional[int], fetch_interval: int diff --git a/qiskit_scaleway/backends/qsim/job.py b/qiskit_scaleway/backends/qsim/job.py index 0bd9516..24463b6 100644 --- a/qiskit_scaleway/backends/qsim/job.py +++ b/qiskit_scaleway/backends/qsim/job.py @@ -74,28 +74,24 @@ def submit(self, session_id: str) -> None: name=self.backend().name, version=self.backend().version, options=options, - frozenset=True, ) client_data = ClientData( user_agent=USER_AGENT, - frozenset=True, ) - computation_model_dict = QuantumComputationModel( + computation_model_json = QuantumComputationModel( programs=programs, backend=backend_data, client=client_data, - frozenset=True, - ).to_dict() + ).to_json_str() - computation_parameters_dict = QuantumComputationParameters( + computation_parameters_json = QuantumComputationParameters( shots=options.pop("shots"), - frozenset=True, - ).to_dict() + ).to_json_str() model = self._client.create_model( - payload=computation_model_dict, + payload=computation_model_json, ) if not model: @@ -105,7 +101,7 @@ def submit(self, session_id: str) -> None: name=self._name, session_id=session_id, model_id=model.id, - parameters=computation_parameters_dict, + parameters=computation_parameters_json, ).id def __to_cirq_result(self, program_result: QuantumProgramResult) -> "cirq.Result": @@ -143,11 +139,14 @@ def result( conv_method = match.get(format, self.__to_qiskit_result) - results = list( + program_results = list( map( lambda r: conv_method(self._extract_payload_from_response(r)), job_results, ) ) - return results + if len(program_results) == 1: + return program_results[0] + + return program_results From d075016138a4f7f806aa56342b007a86b4d09964 Mon Sep 17 00:00:00 2001 From: Valentin Macheret Date: Mon, 3 Nov 2025 19:17:20 +0100 Subject: [PATCH 4/5] feat(qio): fix cirq --- qiskit_scaleway/backends/qsim/job.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/qiskit_scaleway/backends/qsim/job.py b/qiskit_scaleway/backends/qsim/job.py index 24463b6..9434bce 100644 --- a/qiskit_scaleway/backends/qsim/job.py +++ b/qiskit_scaleway/backends/qsim/job.py @@ -62,13 +62,10 @@ def submit(self, session_id: str) -> None: # Note 2: Qsim can only handle one circuit at a time circuit = RemoveBarriers()(self._circuits[0]) - programs = [ - QuantumProgram.from_qiskit_circuit( - circuit, QuantumProgramSerializationFormat.QASM_V2 - ) - ] + programs = [QuantumProgram.from_qiskit_circuit(circuit)] options.pop("circuit_memoization_size") + shots = options.pop("shots") backend_data = BackendData( name=self.backend().name, @@ -87,7 +84,7 @@ def submit(self, session_id: str) -> None: ).to_json_str() computation_parameters_json = QuantumComputationParameters( - shots=options.pop("shots"), + shots=shots, ).to_json_str() model = self._client.create_model( From ed71c6af2e977ac1a98e050ef2082995307c5a97 Mon Sep 17 00:00:00 2001 From: Valentin Macheret Date: Thu, 6 Nov 2025 13:51:40 +0100 Subject: [PATCH 5/5] feat(noise): better handling ser noise model --- qiskit_scaleway/backends/base_job.py | 7 ++++++- qiskit_scaleway/backends/qsim/job.py | 6 +++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/qiskit_scaleway/backends/base_job.py b/qiskit_scaleway/backends/base_job.py index 6d1a5c1..03399b0 100644 --- a/qiskit_scaleway/backends/base_job.py +++ b/qiskit_scaleway/backends/base_job.py @@ -54,6 +54,7 @@ def __init__( self._client = client self._circuits = circuits self._config = config + self._last_progress_message = "" @property def name(self): @@ -68,6 +69,9 @@ def status(self) -> JobStatus: "completed": JobStatus.DONE, } + if job.progress_message is not None: + self._last_progress_message = job.progress_message + return status_mapping.get(job.status, JobStatus.ERROR) def submit(self, session_id: str) -> None: @@ -111,6 +115,7 @@ def submit(self, session_id: str) -> None: if not model: raise RuntimeError("Failed to push circuit data") + self._last_progress_message = "" self._job_id = self._client.create_job( name=self._name, session_id=session_id, @@ -177,6 +182,6 @@ def _wait_for_result( return self._client.list_job_results(self._job_id) if status == JobStatus.ERROR: - raise JobError("Job error") + raise JobError(f"Job failed: {self._last_progress_message}") time.sleep(fetch_interval) diff --git a/qiskit_scaleway/backends/qsim/job.py b/qiskit_scaleway/backends/qsim/job.py index 9434bce..f9a4404 100644 --- a/qiskit_scaleway/backends/qsim/job.py +++ b/qiskit_scaleway/backends/qsim/job.py @@ -62,7 +62,11 @@ def submit(self, session_id: str) -> None: # Note 2: Qsim can only handle one circuit at a time circuit = RemoveBarriers()(self._circuits[0]) - programs = [QuantumProgram.from_qiskit_circuit(circuit)] + programs = [ + QuantumProgram.from_qiskit_circuit( + circuit, QuantumProgramSerializationFormat.QASM_V2 + ) + ] options.pop("circuit_memoization_size") shots = options.pop("shots")