Skip to content

Commit 27d70c8

Browse files
authored
Release/0.35.0 (#71)
1 parent 9494d93 commit 27d70c8

File tree

10 files changed

+111
-40
lines changed

10 files changed

+111
-40
lines changed

.pylintrc

-2
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,13 @@ enable=
2222
line-too-long,
2323
lost-exception,
2424
missing-kwoa,
25-
mixed-indentation,
2625
mixed-line-endings,
2726
not-callable,
2827
no-value-for-parameter,
2928
nonexistent-operator,
3029
not-in-loop,
3130
pointless-statement,
3231
redefined-builtin,
33-
relative-import,
3432
return-arg-in-generator,
3533
return-in-init,
3634
return-outside-function,

_metadata.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
__extension_version__ = "0.34.0"
1+
__extension_version__ = "0.35.0"
22
__extension_name__ = "pytket-qiskit"

docs/changelog.rst

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Changelog
22
~~~~~~~~~
33

4+
0.35.0 (February 2023)
5+
----------------------
6+
7+
* Automatically use IBMQ token if saved in pytket config and not saved in qiskit
8+
config.
9+
* Update qiskit version to 0.40.
10+
* Update code to remove some deprecation warnings.
11+
* Work around https://github.com/Qiskit/qiskit-terra/issues/7865.
12+
413
0.34.0 (January 2023)
514
---------------------
615

docs/intro.txt

+11
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ If you are a member of an IBM hub then you can add this information to ``set_ibm
4242

4343
set_ibmq_config(ibmq_api_token=ibm_token, hub='your hub', group='your group', project='your project')
4444

45+
Alternatively you can use the following qiskit commands to save your credentials
46+
locally without saving the token in pytket config:
47+
48+
::
49+
50+
from qiskit import IBMQ
51+
from qiskit_ibm_runtime import QiskitRuntimeService
52+
53+
IBMQ.save_account(token=ibm_token)
54+
QiskitRuntimeService.save_account(channel="ibm_quantum", token=ibm_token)
55+
4556
To see which devices you can access you can use the ``available_devices`` method on the ``IBMQBackend`` or ``IBMQEmulatorBackend``. Note that it is possible to pass ``hub``, ``group`` and ``project`` parameters to this method. This allows you to see which devices are accessible through your IBM hub.
4657

4758
::

pytket/extensions/qiskit/backends/aer.py

+10-15
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,11 @@
3232

3333
import numpy as np
3434

35-
from qiskit import Aer # type: ignore
36-
from qiskit.providers.aer.library import ( # type: ignore # pylint: disable=unused-import
37-
save_expectation_value,
38-
)
3935
from qiskit.providers.aer.noise import NoiseModel # type: ignore
4036
from qiskit.quantum_info.operators import Pauli as qk_Pauli # type: ignore
41-
from qiskit.quantum_info.operators.symplectic.pauli_table import PauliTable # type: ignore
4237
from qiskit.quantum_info.operators.symplectic.sparse_pauli_op import SparsePauliOp # type: ignore
38+
from qiskit_aer import Aer # type: ignore
39+
from qiskit_aer.library import save_expectation_value # type: ignore # pylint: disable=unused-import
4340

4441
from pytket.backends import Backend, CircuitNotRunError, CircuitStatus, ResultHandle
4542
from pytket.backends.backendinfo import BackendInfo
@@ -695,14 +692,12 @@ def _sparse_to_zx_tup(
695692
def _qubitpauliop_to_sparsepauliop(
696693
operator: QubitPauliOperator, n_qubits: int
697694
) -> SparsePauliOp:
698-
n_ops = len(operator._dict)
699-
table_array = np.zeros((n_ops, 2 * n_qubits), dtype=np.bool_)
700-
coeffs = np.zeros(n_ops, dtype=np.float64)
701-
702-
for i, (term, coeff) in enumerate(operator._dict.items()):
703-
coeffs[i] = coeff
704-
z, x = _sparse_to_zx_tup(term, n_qubits)
705-
table_array[i, :n_qubits] = x
706-
table_array[i, n_qubits:] = z
695+
strings, coeffs = [], []
696+
for term, coeff in operator._dict.items():
697+
termmap = term.map
698+
strings.append(
699+
"".join(termmap.get(Qubit(i), Pauli.I).name for i in range(n_qubits))
700+
)
701+
coeffs.append(coeff)
707702

708-
return SparsePauliOp(PauliTable(table_array), coeffs)
703+
return SparsePauliOp(strings, coeffs)

pytket/extensions/qiskit/backends/ibm.py

+61-17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from ast import literal_eval
1818
from collections import Counter
1919
import json
20+
from time import sleep
2021
from typing import (
2122
cast,
2223
List,
@@ -33,7 +34,12 @@
3334
import qiskit # type: ignore
3435
from qiskit import IBMQ
3536
from qiskit.primitives import SamplerResult # type: ignore
36-
from qiskit.tools.monitor import job_monitor # type: ignore
37+
38+
39+
# RuntimeJob has no queue_position attribute, which is referenced
40+
# via job_monitor see-> https://github.com/CQCL/pytket-qiskit/issues/48
41+
# therefore we can't use job_monitor until fixed
42+
# from qiskit.tools.monitor import job_monitor # type: ignore
3743
from qiskit.result.distributions import QuasiDistribution # type: ignore
3844
from qiskit_ibm_runtime import ( # type: ignore
3945
QiskitRuntimeService,
@@ -113,6 +119,23 @@ def __init__(self) -> None:
113119
)
114120

115121

122+
def _save_ibmq_auth(qiskit_config: Optional[QiskitConfig]) -> None:
123+
token = None
124+
if qiskit_config is not None:
125+
token = qiskit_config.ibmq_api_token
126+
if not IBMQ.active_account():
127+
if IBMQ.stored_account():
128+
IBMQ.load_account()
129+
else:
130+
if token is not None:
131+
IBMQ.save_account(token)
132+
else:
133+
raise NoIBMQAccountError()
134+
if not QiskitRuntimeService.saved_accounts():
135+
if token is not None:
136+
QiskitRuntimeService.save_account(channel="ibm_quantum", token=token)
137+
138+
116139
class IBMQBackend(Backend):
117140
_supports_shots = False
118141
_supports_counts = True
@@ -189,17 +212,7 @@ def _get_provider(
189212
project: Optional[str],
190213
qiskit_config: Optional[QiskitConfig],
191214
) -> "AccountProvider":
192-
if not IBMQ.active_account():
193-
if IBMQ.stored_account():
194-
IBMQ.load_account()
195-
else:
196-
if (
197-
qiskit_config is not None
198-
and qiskit_config.ibmq_api_token is not None
199-
):
200-
IBMQ.save_account(qiskit_config.ibmq_api_token)
201-
else:
202-
raise NoIBMQAccountError()
215+
_save_ibmq_auth(qiskit_config)
203216
provider_kwargs: Dict[str, Optional[str]] = {}
204217
if hub:
205218
provider_kwargs["hub"] = hub
@@ -251,19 +264,39 @@ def _get_backend_info(cls, backend: "_QiskIBMQBackend") -> BackendInfo:
251264
filtered_characterisation = {
252265
k: v for k, v in characterisation.items() if k in characterisation_keys
253266
}
267+
# see below for references for config definitions
268+
# quantum-computing.ibm.com/services/resources/docs/resources/manage/systems/:
269+
# midcircuit-measurement/
270+
# dynamic-circuits/feature-table
254271
supports_mid_measure = config.simulator or config.multi_meas_enabled
255-
supports_fast_feedforward = False
272+
supports_fast_feedforward = (
273+
hasattr(config, "supported_features")
274+
and "qasm3" in config.supported_features
275+
)
276+
256277
# simulator i.e. "ibmq_qasm_simulator" does not have `supported_instructions`
257278
# attribute
279+
supports_reset = (
280+
hasattr(config, "supported_instructions")
281+
and "reset" in config.supported_instructions
282+
)
258283
gate_set = _tk_gate_set(backend)
259284
backend_info = BackendInfo(
260285
cls.__name__,
261286
backend.name(),
262287
__extension_version__,
263288
arch,
264-
gate_set,
289+
gate_set.union(
290+
{
291+
OpType.RangePredicate,
292+
OpType.Conditional,
293+
}
294+
)
295+
if supports_fast_feedforward
296+
else gate_set,
265297
supports_midcircuit_measurement=supports_mid_measure,
266298
supports_fast_feedforward=supports_fast_feedforward,
299+
supports_reset=supports_reset,
267300
all_node_gate_errors=characterisation["NodeErrors"],
268301
all_edge_gate_errors=characterisation["EdgeErrors"],
269302
all_readout_errors=characterisation["ReadoutErrors"],
@@ -382,6 +415,7 @@ def process_circuits(
382415
Supported kwargs: `postprocess`.
383416
"""
384417
circuits = list(circuits)
418+
385419
n_shots_list = Backend._get_n_shots_as_list(
386420
n_shots,
387421
len(circuits),
@@ -428,7 +462,10 @@ def process_circuits(
428462
options.transpilation.skip_transpilation = True
429463
options.execution.shots = n_shots
430464
sampler = Sampler(session=self._session, options=options)
431-
job = sampler.run(circuits=qcs)
465+
job = sampler.run(
466+
circuits=qcs,
467+
dynamic=self.backend_info.supports_fast_feedforward,
468+
)
432469
job_id = job.job_id
433470
for i, ind in enumerate(indices_chunk):
434471
handle_list[ind] = ResultHandle(
@@ -484,9 +521,16 @@ def get_result(self, handle: ResultHandle, **kwargs: KwargTypes) -> BackendResul
484521
except Exception as e:
485522
warn(f"Unable to retrieve job {jobid}: {e}")
486523
raise CircuitNotRunError(handle)
487-
524+
# RuntimeJob has no queue_position attribute, which is referenced
525+
# via job_monitor see-> https://github.com/CQCL/pytket-qiskit/issues/48
526+
# therefore we can't use job_monitor until fixed
488527
if self._monitor and job:
489-
job_monitor(job)
528+
# job_monitor(job)
529+
status = job.status()
530+
while status.name not in ["DONE", "CANCELLED", "ERROR"]:
531+
status = job.status()
532+
print("Job status is", status.name)
533+
sleep(10)
490534

491535
res = job.result(timeout=kwargs.get("timeout", None))
492536
for circ_index, (r, d) in enumerate(zip(res.quasi_dists, res.metadata)):

setup.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,9 @@
4545
include_package_data=True,
4646
install_requires=[
4747
"pytket ~= 1.11",
48-
"qiskit ~= 0.39.0",
49-
"qiskit_ibm_runtime ~= 0.8.0",
48+
"qiskit ~= 0.40.0",
49+
"qiskit-ibm-runtime ~= 0.8.0",
50+
"qiskit-aer ~= 0.11.2",
5051
],
5152
classifiers=[
5253
"Environment :: Console",

tests/backend_test.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -939,11 +939,24 @@ def test_ibmq_mid_measure(manila_backend: IBMQBackend) -> None:
939939
b = manila_backend
940940
ps = b.default_compilation_pass(0)
941941
ps.apply(c)
942-
# c = b.get_compiled_circuit(c)
943942
assert not NoMidMeasurePredicate().verify(c)
944943
assert b.valid_circuit(c)
945944

946945

946+
@pytest.mark.skipif(skip_remote_tests, reason=REASON)
947+
def test_ibmq_conditional(manila_backend: IBMQBackend) -> None:
948+
c = Circuit(3, 2).H(1).CX(1, 2).Measure(0, 0).Measure(1, 1)
949+
c.add_barrier([0, 1, 2])
950+
ar = c.add_c_register("a", 1)
951+
c.CX(1, 0).H(0).X(2, condition=reg_eq(ar, 0)).Measure(Qubit(2), ar[0])
952+
953+
b = manila_backend
954+
assert b.backend_info.supports_fast_feedforward
955+
compiled = b.get_compiled_circuit(c)
956+
assert not NoMidMeasurePredicate().verify(compiled)
957+
assert b.valid_circuit(compiled)
958+
959+
947960
@pytest.mark.skipif(skip_remote_tests, reason=REASON)
948961
def test_compile_x(manila_backend: IBMQBackend) -> None:
949962
# TKET-1028

tests/qiskit_backend_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
from qiskit.providers.ibmq import AccountProvider # type: ignore
2323
from qiskit.opflow import CircuitStateFn, CircuitSampler # type: ignore
2424
from qiskit.providers import JobStatus # type: ignore
25-
from qiskit.providers.aer import Aer # type: ignore
2625
from qiskit.utils import QuantumInstance # type: ignore
2726
from qiskit.algorithms import Grover, AmplificationProblem # type: ignore
2827
from qiskit.transpiler.exceptions import TranspilerError # type: ignore
2928
from qiskit.transpiler.passes import Unroller # type: ignore
29+
from qiskit_aer import Aer # type: ignore
3030

3131
from pytket.extensions.qiskit import (
3232
AerBackend,

tests/qiskit_convert_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
QuantumRegister,
2424
ClassicalRegister,
2525
execute,
26-
Aer,
2726
IBMQ,
2827
)
2928
from qiskit.opflow import PauliOp, PauliSumOp, PauliTrotterEvolution, Suzuki # type: ignore
@@ -33,6 +32,7 @@
3332
from qiskit.circuit.library import RYGate, MCMT # type: ignore
3433
import qiskit.circuit.library.standard_gates as qiskit_gates # type: ignore
3534
from qiskit.circuit import Parameter # type: ignore
35+
from qiskit_aer import Aer # type: ignore
3636
from pytket.circuit import ( # type: ignore
3737
Circuit,
3838
CircBox,

0 commit comments

Comments
 (0)