Giter VIP home page Giter VIP logo

pytket-qiskit's Introduction

pytket-qiskit

Slack Stack Exchange

Pytket is a python module for interfacing with tket, a quantum computing toolkit and optimising compiler developed by Quantinuum.

pytket-qiskit is an extension to pytket that allows pytket circuits to be run on IBM backends and simulators, as well as conversion to and from Qiskit representations.

Some useful links:

Getting started

pytket-qiskit is available for Python 3.10, 3.11 and 3.12, on Linux, MacOS and Windows. To install, run:

pip install pytket-qiskit

This will install pytket if it isn't already installed, and add new classes and methods into the pytket.extensions namespace.

Bugs, support and feature requests

Please file bugs and feature requests on the Github issue tracker.

There is also a Slack channel for discussion and support. Click here to join.

Development

To install an extension in editable mode, simply change to its subdirectory within the modules directory, and run:

pip install -e .

Contributing

Pull requests are welcome. To make a PR, first fork the repo, make your proposed changes on the main branch, and open a PR from your fork. If it passes tests and is accepted after review, it will be merged in.

Code style

Formatting

All code should be formatted using black, with default options. This is checked on the CI. The CI is currently using version 20.8b1.

Type annotation

On the CI, mypy is used as a static type checker and all submissions must pass its checks. You should therefore run mypy locally on any changed files before submitting a PR. Because of the way extension modules embed themselves into the pytket namespace this is a little complicated, but it should be sufficient to run the script modules/mypy-check (passing as a single argument the root directory of the module to test). The script requires mypy 0.800 or above.

Linting

We use pylint on the CI to check compliance with a set of style requirements (listed in .pylintrc). You should run pylint over any changed files before submitting a PR, to catch any issues.

Tests

To run the tests for a module:

  1. cd into that module's tests directory;
  2. ensure you have installed pytest, hypothesis, and any modules listed in the test-requirements.txt file (all via pip);
  3. run pytest.

When adding a new feature, please add a test for it. When fixing a bug, please add a test that demonstrates the fix.

pytket-qiskit's People

Contributors

calmaccq avatar cqc-alec avatar cqc-melf avatar dependabot[bot] avatar doug-q avatar irfankhan10 avatar mickahell avatar monitsharma avatar salmma avatar sjdilkes avatar trvto avatar yao-cqc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pytket-qiskit's Issues

[CI] [examples] Test notebooks using `IBMQEmulatorBackend` on the CI

When run on the CI, it seems that the IBMQEmulatorBackend initialization requires a token to be passed explicitly. This is what we do in the tests on the pytket-qiskit repo. We may need to do something similar here. Currently these notebooks are skipped by the check-examples script.

RuntimeError when using qiskit_to_tk with certain gates

I get a RuntimeError when using qiskit_to_tk with certain quantum circuit/gates. One example is the following:

from qiskit.circuit.library import TwoLocal
from pytket.extensions.qiskit import qiskit_to_tk
import numpy as np
qc = TwoLocal(2, "ry", "cx", entanglement="full", reps=3)
qc = qc.bind_parameters(np.random.rand(qc.num_parameters))
qc_tket = qiskit_to_tk(qc)

leading to the error

---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
/var/folders/<...>.py in <module>
      5 qc = qc.bind_parameters(np.random.rand(qc.num_parameters))
      6 
----> 7 qc_tket = qiskit_to_tk(qc)

~/<...>/site-packages/pytket/extensions/qiskit/qiskit_convert.py in qiskit_to_tk(qcirc, preserve_param_uuid)
    374         phase=param_to_tk(qcirc.global_phase),
    375     )
--> 376     builder.add_qiskit_data(qcirc.data)
    377     return builder.circuit()
    378 

~/<...>/site-packages/pytket/extensions/qiskit/qiskit_convert.py in add_qiskit_data(self, data)
    330                         i.name, subc, list(subc.free_symbols())
    331                     )
--> 332                     self.tkc.add_custom_gate(gate_def, params, qubits + bits)
    333             elif optype == OpType.CU3 and type(i) == qiskit_gates.CUGate:
    334                 if i.params[-1] == 0:

RuntimeError: Gate has an invalid number of parameters

Here, the Qiskit QuantumCircuit contains just one TwoLocal gate.
However, when I decompose the quantum circuit first, the transformation works:

qc_tket = qiskit_to_tk(qc.decompose())

Similar errors occur when trying to transform other circuits with other non-openqasm gates.

I used python v3.9.7, pytket_qiskit v0.32.0, pytket v1.9.0, and qiskit v0.39.3 under Mac OS 13.0.1.

Limited handling of `ControlledGate`(s) in `qiskit_to_tk`

Following PR #49 qiskit ContolledGates where the base gate is supported should be converted to QContolBoxes in the converted circuit.

However the ability to do this is currently limited. Consider the following example with the CSGate.

from qiskit import QuantumCircuit
from qiskit.circuit.library.standard_gates import CSGate
from pytket.extensions.qiskit import qiskit_to_tk

qc = QuantumCircuit(2)
qc.append(CSGate(), [0, 1])
tkc = qiskit_to_tk(qc)

This gives KeyError: <class 'qiskit.circuit.library.standard_gates.s.CSGate'>

However if instead I define a Controlled S gate manually it works fine.

from qiskit.circuit.library.standard_gates import SGate

cs = SGate().control(1)
qc2 = QuantumCircuit(2)
qc2.append(cs , [0, 1])
tkc2 = qiskit_to_tk(qc2)
print(tkc2.get_commands())

This gives
[qif (q[0]) CircBox q[1];]

So the QControlBox conversion works if the controlled gate is defined manually.

This is due to this line. The type(instr) == ControlledGate check returns None for gates which inherit from ControlledGate.

I can fix this locally by using if isinstance(instr, ControlledGate) instead as this checks for inheritance. Howver this leads to test failures elsewhere as our current logic would convert a bunch of known qiskit gates to QControlBox es.

``AerStateBackend`` doesn't support ``Measurement`` and ``Reset``

Tested with 0.37.1

from pytket.extensions.qiskit import AerStateBackend
from pytket.circuit import Circuit,OpType
b = AerStateBackend()
c = Circuit(1,1).H(0).Measure(0,0).add_gate(OpType.Reset, [0]).H(0)
res = b.run_circuit(c)

raises CircuitNotValidError.

I've added Measurement and Reset to the gateset and tested locally, the backend works fine.

The capacity of the AerUnitaryBackend should also be checked.

Conversion from pytket to qiskit fails for circuits containing conditions on a partial register

from pytket.circuit import Circuit
from pytket.extensions.qiskit import tk_to_qiskit

c = Circuit(1, 2)
c.X(0, condition_bits=[0], condition_value=1)

tk_to_qiskit(c)

Output:

NotImplementedError: OpenQASM conditions must be an entire register

The error message is misleading because we are not using OpenQASM for the conversion. It should be possible to convert such circuits to qiskit.

IBMQBackend cannot obtain ibm_seattle device information

Using pytket-qiskit, we cannot access to ibm_seattle(433 qubits).

ibm_token = your ibm token
from qiskit import IBMQ
IBMQ.save_account(ibm_token,hub=your hub,group=your group,project=your project, overwrite=True)
from pytket.extensions.qiskit.backends.config import set_ibmq_config
set_ibmq_config(ibmq_api_token=ibm_token,hub=your hub,group=your group,project=your project)
from pytket.extensions.qiskit import IBMQBackend
list_backend=IBMQBackend.available_devices(hub=your hub,group=your group,project=your project)
for i in range(len(list_backend)):
    print(list_backend[i].device_name)

pytket-qiskit is using api "IBMQ" to obtain backend information, but there seems to be a problem with api "IBMQ" and information on ibm_seattle(433) is not being obtained. If we use from qiskit_ibm_provider import IBMProvider as below, we can obtain ibm_seattle(433) information.

from qiskit_ibm_provider import IBMProvider
IBMProvider.save_account(token=ibm_token,overwrite=True)
provider = IBMProvider()
hub = your hub
group = your group
project = your project
backend_name = "ibm_seattle"
backend = provider.get_backend(backend_name, instance=f"{hub}/{group}/{project}")
provider.backends()

https://github.com/CQCL/pytket-qiskit/blob/bfcfbb0f18b024f42836a7933605b68ab62f1d8a/pytket/extensions/qiskit/backends/ibm.py#LL35C1-L35C1

Eliminate warnings from test run

Some of these may be outside our control, in which case we can suppress them; others we should fix:

../env/lib/python3.10/site-packages/_pytest/fixtures.py:227
  /home/alec/r/pytket-qiskit/env/lib/python3.10/site-packages/_pytest/fixtures.py:227: PendingDeprecationWarning: The qiskit.Aer entry point will be deprecated in a future release and subsequently removed. Instead you should use this directly from the root of the qiskit-aer package.
    fixturemarker: Optional[FixtureFunctionMarker] = getattr(

tests/backend_test.py::test_operator
tests/backend_test.py::test_operator
tests/backend_test.py::test_operator
tests/backend_test.py::test_operator
tests/backend_test.py::test_expectation_bug
tests/backend_test.py::test_aer_placed_expectation
tests/backend_test.py::test_aer_placed_expectation
  /home/alec/r/pytket-qiskit/pytket/extensions/qiskit/backends/aer.py:710: PendingDeprecationWarning: The PauliTable class has been superseded by PauliList and is pending deprecation. This class will be deprecated in the future release and subsequently removed after that.
    return SparsePauliOp(PauliTable(table_array), coeffs)

tests/backend_test.py::test_operator
tests/backend_test.py::test_expectation_bug
tests/backend_test.py::test_aer_placed_expectation
tests/backend_test.py::test_aer_placed_expectation
  /home/alec/r/pytket-qiskit/env/lib/python3.10/site-packages/qiskit/quantum_info/operators/symplectic/sparse_pauli_op.py:131: ComplexWarning: Casting complex values to real discards the imaginary part
    self._coeffs = np.asarray((-1j) ** (phase - count_y) * coeffs, dtype=coeffs.dtype)

tests/qiskit_backend_test.py: 12 warnings
  /home/alec/r/pytket-qiskit/env/lib/python3.10/site-packages/qiskit_aer/noise/device/models.py:365: UserWarning: Device model returned an invalid T_2 relaxation time greater than the theoretical maximum value 2 * T_1 (94238.37625242842 > 2 * 2953.117923413739). Truncating to maximum value.
    warn("Device model returned an invalid T_2 relaxation time greater than"

tests/qiskit_backend_test.py::test_qiskit_counts
tests/qiskit_backend_test.py::test_qiskit_counts
  /home/alec/r/pytket-qiskit/env/lib/python3.10/site-packages/qiskit_aer/noise/device/models.py:365: UserWarning: Device model returned an invalid T_2 relaxation time greater than the theoretical maximum value 2 * T_1 (9.423837625242843e-05 > 2 * 2.9531179234137392e-06). Truncating to maximum value.
    warn("Device model returned an invalid T_2 relaxation time greater than"

tests/qiskit_backend_test.py::test_grover
  /home/alec/r/pytket-qiskit/tests/qiskit_backend_test.py:166: PendingDeprecationWarning: The quantum_instance argument has been superseded by the sampler argument. This argument will be deprecated in a future release and subsequently removed after that.
    grover = Grover(quantum_instance=qinstance)

tests/qiskit_backend_test.py::test_unsupported_gateset
  /home/alec/r/pytket-qiskit/tests/qiskit_backend_test.py:184: PendingDeprecationWarning: The quantum_instance argument has been superseded by the sampler argument. This argument will be deprecated in a future release and subsequently removed after that.
    grover = Grover(quantum_instance=qinstance)

tests/qiskit_backend_test.py::test_unsupported_gateset
  /home/alec/r/pytket-qiskit/tests/qiskit_backend_test.py:197: PendingDeprecationWarning: The quantum_instance argument has been superseded by the sampler argument. This argument will be deprecated in a future release and subsequently removed after that.
    grover = Grover(quantum_instance=qinstance)

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html

default_compilation_pass does not work new IBM device

New IBMQ devices ibm_seattle(433), ibm_sherbrooke(127), ibm_brisbane(127) use a new primitive gate set { noop X Measure RangePredicate Reset Barrier Rz Conditional SX ECR } which is not {OpType.CX, OpType.X, OpType.SX, OpType.Rz}. So default_compilation_pass does not work.

I found that GateSetPredicate of rebase_pass does not match GateSetPredicate of required_predicates.

from pytket.extensions.qiskit import IBMQBackend
ibm_backend = IBMQBackend("ibm_sherbrooke",token=ibm_token)
#ibm_backend = IBMQBackend("ibm_brisbane",token=ibm_token)
ibm_backend.required_predicates
ibm_backend.rebase_pass()

def rebase_pass(self) -> BasePass:
return auto_rebase_pass(
{OpType.CX, OpType.X, OpType.SX, OpType.Rz},
)

Add support for general controlled gates in converters

For example:

from qiskit import QuantumCircuit, QuantumRegister
from qiskit.circuit.library.standard_gates import HGate
from pytket.extensions.qiskit.qiskit_convert import tk_to_qiskit

qr = QuantumRegister(3)
qc = QuantumCircuit(qr)
c3h_gate = HGate().control(2)
qc.append(c3h_gate, qr)
c = tk_to_qiskit(qc)

Currently throws a NotImplementedError.

We could use the QControlBox for this.

`tk_to_qiskit`: Support of `Qiskit.QuantumCircuit.Layout` Attribute

Hello,

in Qiskit v0.43.0 (Link: https://qiskit.org/documentation/locale/de_DE/release_notes.html#:~:text=Added%20a%20new%20attribute%2C%20layout), the layout attribute is officially introduced that stores a TranspileLayout to preserve mapping information of a compiled and mapped quantum circuit (e.g., initial_layout, input_qubit_mapping, final_layout).

I was wondering whether it is planned that pytket-qiskit's tk_to_qiskit supports/sets this attribute when transforming a quantum circuit mapped using pytket to a qiskit circuit.

IBMQBackend.available_devices type error

For IBMQBackend I believe the type for BackendInfo.device_name is incorrect on the BackendInfos returned from available_devices. It should return a str but instead returns a method.

Minimal example:

from pytket.extensions.qiskit import IBMQBackend

from qiskit.providers.ibmq import IBMQFactory

account_provider = IBMQFactory().enable_account(
    token=token,
    hub="ibm-q",
    group="open",
    project="main",
)

backend_infos = IBMQBackend.available_devices(provider=account_provider)

print(backend_infos[0].device_name)

Outputs:

<bound method BackendV1.name of <IBMQSimulator('ibmq_qasm_simulator') from IBMQ(hub='ibm-q', group='open', project='main')>>

Missing XXPlusYYGate

The qiskit.circuit.library.standard_gates.xx_plus_yy.XXPlusYYGate is currently not supported in the qiskit_to_tk conversion, we should add that.

Some qiskit gates missing from the _known_qiskit_gate list

After using qiskit.circuit.random.random_circuit for generating random qiskit circuits, if you try to transform those circuits to tket with pytket.extensions.qiskit.qiskit_to_tk, the process fails since there are some gates that are not recognised. The following is a list of the gates not recognised (beware that the list might not be complete):

qiskit.circuit.library.standard_gates.sx.CSXGate
qiskit.circuit.library.standard_gates.z.CCZGate
qiskit.circuit.library.standard_gates.rzx.RZXGate
qiskit.circuit.library.standard_gates.xx_plus_yy.XXPlusYYGate
qiskit.circuit.library.standard_gates.dcx.DCXGate
qiskit.circuit.library.standard_gates.xx_minus_yy.XXMinusYYGate
qiskit.circuit.library.standard_gates.s.CSdgGate
qiskit.circuit.library.standard_gates.x.RCCXGate
qiskit.circuit.library.standard_gates.s.CSGate

`qiskit_to_tk`: KeyError for certain gates

The qiskit_to_tk transformation fails when certain gates are present in the original Qiskit.QuantumCircuit and throws a respective KeyError.

One example can be seen here:

from qiskit import QuantumCircuit
from qiskit.circuit.random import random_circuit
from pytket.extensions.qiskit import qiskit_to_tk

qc = random_circuit(8, depth=10, measure=False, seed=10)
qc_tket = qiskit_to_tk(qc)

Resulting in: KeyError: <class 'qiskit.circuit.library.standard_gates.xx_plus_yy.XXPlusYYGate'>

I could imagine that the problem occurs for gates which are not part of the openQASM2.0 gates. But there are even gates from that gateset which lead to the same error, for example here:

from qiskit import QuantumCircuit
from pytket.extensions.qiskit import qiskit_to_tk

qc = QuantumCircuit(3)
qc.rccx(0,1,2)
qc_tket = qiskit_to_tk(qc)

Resulting in: KeyError: <class 'qiskit.circuit.library.standard_gates.x.RCCXGate'>

(based on pytket v1.16.0 and qiskit v0.43.1)

TypeError: 'IBMQEmulatorBackend' object is not subscriptable


TypeError Traceback (most recent call last)
Cell In[21], line 4
1 from pytket.placement import NoiseAwarePlacement, GraphPlacement
2 from pytket.extensions.qiskit.qiskit_convert import get_avg_characterisation
----> 4 backend_avg = get_avg_characterisation(backend)
7 avg_char = [node_errors, edge_errors, readout_errors]
9 noise_placer = NoiseAwarePlacement(backend.backend_info.architecture, **avg_char)

File /opt/.qbraid/environments/qbraid_000000/pyenv/lib/python3.9/site-packages/pytket/extensions/qiskit/qiskit_convert.py:791, in get_avg_characterisation(characterisation)
788 map_values_t = Callable[[Callable[[V1], V2], Dict[K, V1]], Dict[K, V2]]
789 map_values: map_values_t = lambda f, d: {k: f(v) for k, v in d.items()}
--> 791 node_errors = cast(Dict[Node, Dict[OpType, float]], characterisation["NodeErrors"])
792 link_errors = cast(
793 Dict[Tuple[Node, Node], Dict[OpType, float]], characterisation["EdgeErrors"]
794 )
795 readout_errors = cast(
796 Dict[Node, List[List[float]]], characterisation["ReadoutErrors"]
797 )

TypeError: 'IBMQEmulatorBackend' object is not subscriptable

[tests] remove deprecation warnings from qiskit backend tests

tests/qiskit_backend_test.py::test_grover
  [...]/tests/qiskit_backend_test.py:164: PendingDeprecationWarning: The quantum_instance argument has been superseded by the sampler argument. This argument will be deprecated in a future release and subsequently removed after that.
    grover = Grover(quantum_instance=qinstance)

`AerStateBackend` gives incorrect results for circuits with implicit qubit permutations

from pytket import Circuit
from pytket.passes import FullPeepholeOptimise
from pytket.extensions.qiskit import AerStateBackend

b = AerStateBackend()
c = Circuit(3).X(0).SWAP(0, 1).SWAP(0, 2)

sv = b.run_circuit(c).get_state()

FullPeepholeOptimise().apply(c)

sv1 = b.run_circuit(c).get_state()

print(sv)
print(sv1.round(4))

Output:

[0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j]

Note that after applying FullPeepholeOptimise() the circuit has an implicit permutation.

Update to qiskit 0.40

Preferably also remove deprecation warnings (IBMQ is deprecated in this version).

Support noise on custom gates

Qiskit permits noise to be added to particular gates, for example as follows:

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit_aer.noise import NoiseModel, depolarizing_error
from qiskit.extensions import UnitaryGate

error = depolarizing_error(0.1, 1)

noise_model = NoiseModel()
noise_model.add_quantum_error(error, 'my_gate', [0])
noise_model.add_basis_gates(['unitary'])

matrix = [[0,1], [1,0]]
gate = UnitaryGate(matrix, label='my_gate')

circ = QuantumCircuit(1)
circ.append(gate, [0])
circ.measure_all()

backend = AerSimulator(noise_model=noise_model)

noise_result = backend.run(circ).result()
noise_result.get_counts()

giving in one instance:

{'0': 46, '1': 978}

as expected. It seems that it's not straightforward to do the same with pytket with something very simple like:

from pytket.extensions.qiskit import AerBackend

tket_backend = AerBackend(noise_model=noise_model)

giving an error ending in:

File /Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/pytket/extensions/qiskit/backends/aer.py:591, in _process_noise_model(noise_model, gate_set)
    589 if len(qubits) == 1:
    590     [q] = qubits
--> 591     optype = _gate_str_2_optype[name]
    592     qubits_set.add(q)
    593     if error["type"] == "qerror":

KeyError: 'my_gate'

Being able to add noise to particular gates would be a great feature to have!

Teleportation circuit compiled with opt level 2 cannot be run on AerBackend due to conditional Phase

c = Circuit()
alice = c.add_q_register("a", 2)
bob = c.add_q_register("b", 1)
data = c.add_c_register("d", 2)
final = c.add_c_register("f", 1)
c.Rx(0.3, alice[0])
c.H(alice[1]).CX(alice[1], bob[0])
c.CX(alice[0], alice[1]).H(alice[0])
c.Measure(alice[0], data[0])
c.Measure(alice[1], data[1])
c.X(bob[0], condition_bits=[data[0], data[1]], condition_value=1)
c.X(bob[0], condition_bits=[data[0], data[1]], condition_value=3)
c.Z(bob[0], condition_bits=[data[0], data[1]], condition_value=2)
c.Z(bob[0], condition_bits=[data[0], data[1]], condition_value=3)
c.Measure(bob[0], final[0])

backend = AerBackend()
c = backend.get_compiled_circuit(c)
handle = backend.process_circuit(c, n_shots=2000)

NotImplementedError: Cannot convert tket Op to Qiskit gate: Phase(0.5)

This is caused by conditional X/Z being converted to conditional Phase, and the latter is not supported by the qiskit converter.

Add CnY and CnZ gates to converters

CnY and CnZ gates are now supported in pytket. The conversion done by tk_to_qiskit should be able to handle these gates.

A test should also be added that covers conversion from a Circuit containing CnY and CnZ operations.

User is not warned about implicit permutations

There appears to be no warning to alert the user that there could be implicit permutations when converting a circuit from pytket to qiskit. Specifically, the user does not know that they need to pass the keyword arg replace_implicit_swaps.

import numpy as np
from pytket import Circuit
from pytket.extensions.qiskit import AerStateBackend, tk_to_qiskit
from qiskit_aer import StatevectorSimulator

b = AerStateBackend()
c = Circuit(3).X(0).SWAP(0, 1).SWAP(0, 2)

c = AerStateBackend().get_compiled_circuit(c, optimisation_level=2)

sv1 = b.run_circuit(c).get_state()

print(sv1.round(4))

qiskit_circ = tk_to_qiskit(c)
print(np.array(StatevectorSimulator().run(qiskit_circ).result().get_statevector()).round(4))

Output:

[0.+0.j 0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]
[0.+0.j 1.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j 0.+0.j]

`IBMQEmulatorBackend` variant that runs locally

Since adoption of qiskit runtime the IBMQEmulatorBackend became a runtime instance of the ibmq_qasm_simulator backend (hosted by IBM). It would still be useful to have a local emulator based on AerBackend using an imported noise model.

Improve error message for failed `qiskit_to_tk` conversion

Currently if users try and convert a qiskit QuantumCircuit with an instruction that is not supported by qiskit_to_tk they get a rather unhelpful error message.

For example

from qiskit import QuantumCircuit
from qiskit.circuit.library import XXPlusYYGate
from pytket.extensions.qiskit import qiskit_to_tk

qc = QuantumCircuit(2)
qc.append(XXPlusYYGate(0.1), [0, 1]) # add unsupported gate

tkc = qiskit_to_tk(qc)

This gives the error

    optype = _known_qiskit_gate[type(instr)]
             ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
KeyError: <class 'qiskit.circuit.library.standard_gates.xx_plus_yy.XXPlusYYGate'

This error could be made more informative.

We should explain that the specific instruction is unsupported and maybe recommend using QuantumCircuit.decompose() to decompose higher level operations before conversion.

Of course we should still add new operations to the converter when we can.

Handle qiskit state preperation circuits in `qiskit_to_tk` converter

Often if we try to convert qiskit circuits which use state preperation gadgets (i.e using QuantumCircuit.initialize) we will need to use QuantumCircuit.decompose() repeatedly in order to avoid a key error in the conversion. This is because the state preperation uses higher level circuit operations which are not supported by the qiskit_to_tk converter.

We now have the StatePreparationBox implemented in TKET as well as multiplexor operations. So we should in theory be able to handle the operations used in state prep directly in the converter without decomposing first.

Order of qubits in statevector is not lexicographic

For example:

from pytket.circuit import Circuit
from pytket.extensions.qiskit import AerStateBackend

backend = AerStateBackend()

c = Circuit()
a = c.add_q_register("a", 1)
b = c.add_q_register("b", 1)
c.X(a[0])

c0 = Circuit(2).X(0)

s = backend.run_circuit(c).get_state()
s0 = backend.run_circuit(c0).get_state()

print(s)
print(s0)

Output:

[0.+0.j 1.+0.j 0.+0.j 0.+0.j]
[0.+0.j 0.+0.j 1.+0.j 0.+0.j]

The statevectors should be the same, but the qubits a[0] and b[0] are mapped in the wrong order.

`IBMQEmulatorBackend` and `IBMQBackend` don't properly enforce `MaxNQubitsPredicate`

If I ask IBMQBackend and IBMQEmulatorBackend which predicates they require with Backend.required_predicates I get the following...

[NoFastFeedforwardPredicate,
 NoSymbolsPredicate,
 GateSetPredicate:{ Rz noop Reset X SX Barrier CX Measure }]

I would've expected MaxNQubitsPredicate to appear on this list.

As its not enforced I can run a 7 qubit circuit on a 5 qubit emulator which shouldn't be possible.

from pytket import Circuit
from pytket.extensions.qiskit import IBMQEmulatorBackend

backend = IBMQEmulatorBackend('ibmq_belem') # Backend is supposed to only support 5 qubits

# Define a 7 qubit circuit that is already in the IBM gateset: {X, SX, CX, Rz} - no compilation needed
circ = Circuit(7).X(0).CX(0, 1).CX(0, 2).CX(0, 3).CX(0, 4).CX(0, 5).CX(0, 6).measure_all() 

result = backend.run_circuit(circ, n_shots=100)
print(result.get_counts) # get some length 7 bitstrings back from the simulator (shouldn't be possible)

However if I compile the circuit first with Backend.get_compiled_circuit an error message is thrown saying the circuit does not respect the MaxNQubitsPredicate. I'm not sure how this is enforced as it does not appear in Backend.required_predicates.

Incorrect circuit in parametrized PauliEvolutionGate

Hi,

I would appreciate your help with looking into the following:

Using
pytket 1.8.1
pytket-qiskit 0.29.0
qiskit 0.38.0,

I tried to run the example below, whose Qiskit's circuit results in eight layers. However, the TKet circuit is shallow, seemingly consisting of only two layers, and the x symbol is absent.
I thought at first to introduce a workaround by changing the line qpodict[QubitPauliString(qubits, qpslist)] = c, which appears in qiskit_convert.py, into qpodict[QubitPauliString(qubits, qpslist)] = c * peg.time.sympify(). However, the resulting circuit is still shallow.
The resulting circuits are not formally equivalent (I tested by converting the TKet circuit back to Qiskit, assigning some x value to both circuits, composing one with another's inverse, and checking the resulting matrix, which is not the identity operator)

from pytket import Circuit
from pytket.extensions.qiskit import qiskit_to_tk
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit.opflow import PauliOp, PauliSumOp, PauliTrotterEvolution, Suzuki
from qiskit.quantum_info import Pauli

evolution_coefficient = "x"

pauli_blocks = [PauliOp(Pauli("XXZ"), coeff=1.0), PauliOp(Pauli("YXY"), coeff=0.5)]
operator: PauliSumOp = sum(pauli_blocks) * Parameter(evolution_coefficient)
evolved_circ_op = PauliTrotterEvolution(trotter_mode=Suzuki(reps=2, order=4)).convert(
    operator.exp_i()
)

qc: QuantumCircuit = evolved_circ_op.primitive
tk_qc: Circuit = qiskit_to_tk(qc)

``qiskit_to_tk`` incorrectly converts multi-controlled gates

This following "00" controlled X gate is incorrectly translated to CCX.

from pytket import Circuit
from pytket.extensions.qiskit import qiskit_to_tk
from qiskit import QuantumCircuit
c = QuantumCircuit(3)
# last arg: activated by state "0"
c.ccx(0,1,2,0)
tk_circ = qiskit_to_tk(c)
print(tk_circ.__repr__())
# [CCX q[0], q[1], q[2]; ]

The results returned from TketJob doesn't contain circuit names

This example in the manual doesn't work with pytket-quantinuum for two reasons:

The first reason is described in #14

The second reason is that the Grover.amplify method uses the name of the grover circuit to retrieve the result from a qiskit.Result object, but the qiskit.Result produced by TketJob.result() doesn't contain this information. See this line of code in qiskit. (i.e. the grover method uses the qc: QuantumCircuit as the key to the Result.get_counts() method, the get_counts method then uses qc.name to find the result)

To reproduce:

b = QuantinuumBackend(device_name="H1-1E")
backend = TketBackend(b, b.default_compilation_pass())
pass_ = Unroller(['u1', 'u2', 'u3', 'cx'])
qinstance = QuantumInstance(backend, pass_manager=pass_)
oracle = QuantumCircuit(2)
oracle.cz(0, 1)

def is_good_state(bitstr):
    return sum(map(int, bitstr)) == 2

problem = AmplificationProblem(oracle=oracle, is_good_state=is_good_state)
grover = Grover(quantum_instance=qinstance)
result = grover.amplify(problem)
print("Top measurement:", result.top_measurement)

--> 381     raise QiskitError('Data for experiment "%s" could not be found.' % key)
    382 if len(exp) == 1:
    383     exp = exp[0]

QiskitError: 'Data for experiment "Grover circuit" could not be found.'

We can probably add a header.name field to the result returned by TketJob.result()

Error when converting qiskit `UnitaryGate` objects in `qiskit_to_tk`

Noticed by @daniel-mills-cqc

The qiskit_to_tk parser seems to assume UnitaryGate objects are 4x4 unitaries and tries to synthesise them with Unitary2qBox (see here and here). However in qiskit UnitaryGate does not have a fixed dimension.

I think we should either handle the cases for converting 1 and 3 qubit unitary gates or give a suitable error message.

from qiskit import QuantumCircuit
from qiskit.extensions import UnitaryGate
from pytket.extensions.qiskit import qiskit_to_tk

matrix = [[1,0], [0,1]] # 2x2 identity matrix
gate = UnitaryGate(matrix, label='my_gate')

circuit = QuantumCircuit(1)
circuit.append(gate, [0])

tk_circuit = qiskit_to_tk(circuit)

gives the error

TypeError: __init__(): incompatible constructor arguments. The following argument types are supported:
    1. pytket._tket.circuit.Unitary2qBox(m: numpy.ndarray[numpy.complex128[4, 4]], basis: pytket._tket.circuit.BasisOrder = <BasisOrder.ilo: 0>)

Invoked with: array([[1.+0.j, 0.+0.j],
       [0.+0.j, 1.+0.j]])

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.