Skip to content

Commit 817f3e0

Browse files
authored
fix issue with conditional and symbolic parameter in conversion (#245)
* fix conditional and symbolic parameter in conversion * remove linebreak from error message * use numpy.pi * remove qasm from error message
1 parent 3ea0f5a commit 817f3e0

File tree

4 files changed

+98
-31
lines changed

4 files changed

+98
-31
lines changed

docs/changelog.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ General:
88

99
* Python 3.12 support added, 3.9 dropped.
1010
* pytket dependency updated to 1.24.
11-
11+
* fix conditional bit in pytket to qiskit conversion
12+
* fix symbolic conversion of parameter in conversion
1213

1314
0.47.0 (January 2024)
1415
---------------------

pytket/extensions/qiskit/qiskit_convert.py

+39-16
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
Parameter,
5353
ParameterExpression,
5454
Reset,
55+
Clbit,
5556
)
5657
from qiskit.circuit.library import (
5758
CRYGate,
@@ -342,11 +343,23 @@ def add_qiskit_data(self, data: "QuantumCircuitData") -> None:
342343
for instr, qargs, cargs in data:
343344
condition_kwargs = {}
344345
if instr.condition is not None:
345-
cond_reg = self.cregmap[instr.condition[0]]
346-
condition_kwargs = {
347-
"condition_bits": [cond_reg[k] for k in range(len(cond_reg))],
348-
"condition_value": instr.condition[1],
349-
}
346+
if type(instr.condition[0]) == ClassicalRegister:
347+
cond_reg = self.cregmap[instr.condition[0]]
348+
condition_kwargs = {
349+
"condition_bits": [cond_reg[k] for k in range(len(cond_reg))],
350+
"condition_value": instr.condition[1],
351+
}
352+
elif type(instr.condition[0]) == Clbit:
353+
cond_reg = self.cregmap[instr.condition[0].register]
354+
condition_kwargs = {
355+
"condition_bits": [cond_reg[instr.condition[0].index]],
356+
"condition_value": instr.condition[1],
357+
}
358+
else:
359+
raise NotImplementedError(
360+
"condition must contain classical bit or register"
361+
)
362+
350363
# Controlled operations may be controlled on values other than all-1. Handle
351364
# this by prepending and appending X gates on the control qubits.
352365
ctrl_state, num_ctrl_qubits = None, None
@@ -653,22 +666,29 @@ def append_tk_command_to_qiskit(
653666
width = op.width # type: ignore
654667
value = op.value # type: ignore
655668
regname = args[0].reg_name
656-
if len(cregmap[regname]) != width:
657-
raise NotImplementedError("OpenQASM conditions must be an entire register")
658669
for i, a in enumerate(args[:width]):
659670
if a.reg_name != regname:
660-
raise NotImplementedError(
661-
"OpenQASM conditions can only use a single register"
662-
)
663-
if a.index != [i]:
664-
raise NotImplementedError(
665-
"OpenQASM conditions must be an entire register in order"
666-
)
671+
raise NotImplementedError("Conditions can only use a single register")
667672
instruction = append_tk_command_to_qiskit(
668673
op.op, args[width:], qcirc, qregmap, cregmap, symb_map, range_preds # type: ignore
669674
)
675+
if len(cregmap[regname]) == width:
676+
for i, a in enumerate(args[:width]):
677+
if a.index != [i]:
678+
raise NotImplementedError(
679+
"""Conditions must be an entire register in\
680+
order or only one bit of one register"""
681+
)
682+
683+
instruction.c_if(cregmap[regname], value)
684+
elif width == 1:
685+
instruction.c_if(cregmap[regname][args[0].index[0]], value)
686+
else:
687+
raise NotImplementedError(
688+
"""Conditions must be an entire register in\
689+
order or only one bit of one register"""
690+
)
670691

671-
instruction.c_if(cregmap[regname], value)
672692
return instruction
673693
# normal gates
674694
qargs = [qregmap[q.reg_name][q.index[0]] for q in args]
@@ -719,7 +739,10 @@ def append_tk_command_to_qiskit(
719739
) from error
720740
params = _get_params(op, symb_map)
721741
g = gatetype(*params)
722-
qcirc.global_phase += phase * sympy.pi
742+
if type(phase) == float:
743+
qcirc.global_phase += phase * np.pi
744+
else:
745+
qcirc.global_phase += phase * sympy.pi
723746
return qcirc.append(g, qargs=qargs)
724747

725748

tests/qiskit_backend_test.py

-2
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
from qiskit.primitives import BackendSampler # type: ignore
2323
from qiskit.providers import JobStatus # type: ignore
2424
from qiskit_algorithms import Grover, AmplificationProblem, AlgorithmError # type: ignore
25-
from qiskit.transpiler import PassManager # type: ignore
26-
from qiskit.transpiler.passes import Unroller # type: ignore
2725
from qiskit_aer import Aer # type: ignore
2826

2927
from qiskit_ibm_provider import IBMProvider # type: ignore

tests/qiskit_convert_test.py

+57-12
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,17 @@
2424
ClassicalRegister,
2525
execute,
2626
)
27-
from qiskit.quantum_info import SparsePauliOp # type: ignore
27+
from qiskit.quantum_info import SparsePauliOp, Statevector, Operator # type: ignore
2828
from qiskit.transpiler import PassManager # type: ignore
2929
from qiskit.circuit.library import RYGate, MCMT, XXPlusYYGate, PauliEvolutionGate, UnitaryGate, RealAmplitudes # type: ignore
3030
import qiskit.circuit.library.standard_gates as qiskit_gates # type: ignore
3131
from qiskit.circuit import Parameter
3232
from qiskit.synthesis import SuzukiTrotter # type: ignore
3333
from qiskit_aer import Aer # type: ignore
34-
from qiskit.quantum_info import Statevector, Operator
34+
from qiskit.transpiler.passes import BasisTranslator # type: ignore
35+
from qiskit.circuit.equivalence_library import StandardEquivalenceLibrary # type: ignore
36+
from qiskit.providers.fake_provider import FakeGuadalupe # type: ignore
37+
from qiskit.circuit.parameterexpression import ParameterExpression # type: ignore
3538

3639
from pytket.circuit import (
3740
Circuit,
@@ -50,7 +53,14 @@
5053
from pytket.extensions.qiskit.qiskit_convert import _gate_str_2_optype
5154
from pytket.extensions.qiskit.tket_pass import TketPass, TketAutoPass
5255
from pytket.extensions.qiskit.result_convert import qiskit_result_to_backendresult
53-
from pytket.passes import RebaseTket, DecomposeBoxes, FullPeepholeOptimise, SequencePass
56+
from pytket.passes import (
57+
RebaseTket,
58+
DecomposeBoxes,
59+
FullPeepholeOptimise,
60+
SequencePass,
61+
CliffordSimp,
62+
)
63+
5464
from pytket.utils.results import (
5565
compare_statevectors,
5666
permute_rows_cols_in_unitary,
@@ -72,6 +82,28 @@ def _get_qiskit_statevector(qc: QuantumCircuit) -> np.ndarray:
7282
return np.array(job.result().data()["statevector"].reverse_qargs().data)
7383

7484

85+
def test_parameterised_circuit_global_phase() -> None:
86+
pass_1 = BasisTranslator(
87+
StandardEquivalenceLibrary,
88+
target_basis=FakeGuadalupe().configuration().basis_gates,
89+
)
90+
pass_2 = CliffordSimp()
91+
92+
qc = QuantumCircuit(2)
93+
qc.ryy(Parameter("MyParam"), 0, 1)
94+
95+
pm = PassManager(pass_1)
96+
qc = pm.run(qc)
97+
98+
tket_qc = qiskit_to_tk(qc)
99+
100+
pass_2.apply(tket_qc)
101+
102+
qc_2 = tk_to_qiskit(tket_qc)
103+
104+
assert type(qc_2.global_phase) == ParameterExpression
105+
106+
75107
def test_classical_barrier_error() -> None:
76108
c = Circuit(1, 1)
77109
c.add_barrier([0], [0])
@@ -398,24 +430,17 @@ def test_conditions() -> None:
398430

399431

400432
def test_condition_errors() -> None:
401-
with pytest.raises(Exception) as errorinfo:
402-
c = Circuit(2, 2)
403-
c.X(0, condition_bits=[0], condition_value=1)
404-
tk_to_qiskit(c)
405-
assert "OpenQASM conditions must be an entire register" in str(errorinfo.value)
406433
with pytest.raises(Exception) as errorinfo:
407434
c = Circuit(2, 2)
408435
b = c.add_c_register("b", 2)
409436
c.X(Qubit(0), condition_bits=[b[0], Bit(0)], condition_value=1)
410437
tk_to_qiskit(c)
411-
assert "OpenQASM conditions can only use a single register" in str(errorinfo.value)
438+
assert "Conditions can only use a single register" in str(errorinfo.value)
412439
with pytest.raises(Exception) as errorinfo:
413440
c = Circuit(2, 2)
414441
c.X(0, condition_bits=[1, 0], condition_value=1)
415442
tk_to_qiskit(c)
416-
assert "OpenQASM conditions must be an entire register in order" in str(
417-
errorinfo.value
418-
)
443+
assert "Conditions must be an entire register in order" in str(errorinfo.value)
419444

420445

421446
def test_correction() -> None:
@@ -857,6 +882,26 @@ def test_ccx_conversion() -> None:
857882
)
858883

859884

885+
def test_conditional_conversion() -> None:
886+
c = Circuit(1, 2, "conditional_circ")
887+
c.X(0, condition_bits=[0], condition_value=1)
888+
889+
c_qiskit = tk_to_qiskit(c)
890+
c_tket = qiskit_to_tk(c_qiskit)
891+
892+
assert c_tket.to_dict() == c.to_dict()
893+
894+
895+
def test_conditional_conversion_2() -> None:
896+
c = Circuit(1, 2, "conditional_circ_2")
897+
c.X(0, condition_bits=[1], condition_value=1)
898+
899+
c_qiskit = tk_to_qiskit(c)
900+
c_tket = qiskit_to_tk(c_qiskit)
901+
902+
assert c_tket.to_dict() == c.to_dict()
903+
904+
860905
# https://github.com/CQCL/pytket-qiskit/issues/100
861906
def test_state_prep_conversion_array_or_list() -> None:
862907
# State prep with list of real amplitudes

0 commit comments

Comments
 (0)