Skip to content

Commit

Permalink
Add support for delay instruction
Browse files Browse the repository at this point in the history
* The backend-dependent time unit dt is left untouched
* All other time units (s, ms, us, ns, ps) are converted to us when
  generating QIR
  • Loading branch information
Julien Dumazert committed Apr 14, 2023
1 parent e8285fa commit 96734a9
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 4 deletions.
14 changes: 10 additions & 4 deletions src/qiskit_qir/visitor.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"cz",
"h",
"reset",
"delay",
"rx",
"ry",
"rz",
Expand All @@ -75,6 +76,7 @@
"m",
"measure",
"reset",
"delay",
"rx",
"ry",
"rz",
Expand All @@ -88,9 +90,7 @@
"z",
]

_NOOP_INSTRUCTIONS = ["delay"]

_SUPPORTED_INSTRUCTIONS = _QUANTUM_INSTRUCTIONS + _NOOP_INSTRUCTIONS
_SUPPORTED_INSTRUCTIONS = _QUANTUM_INSTRUCTIONS


class QuantumCircuitElementVisitor(metaclass=ABCMeta):
Expand Down Expand Up @@ -311,7 +311,13 @@ def __branch():
if self._emit_barrier_calls:
qis.barrier(self._builder)
elif "delay" == instruction.name:
pass
# us is chosen as the default time unit in QIR since it is well
# suited to current performance of qubit implementations.
# When using dt, the backend-dependent time unit, the duration
# value is left untouched.
multipliers = {"s": 1e6, "ms": 1e3, "us": 1, "ns": 1e-3, "ps": 1e-6, "dt": 1}
duration = instruction.duration * multipliers[instruction.unit]
qis.delay(self._builder, duration, *qubits)
elif "swap" == instruction.name:
qis.swap(self._builder, *qubits)
elif "ccx" == instruction.name:
Expand Down
25 changes: 25 additions & 0 deletions tests/test_circuits/basic_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

_measurements = {"measure": "mz"}

_delays = {"delay": "delay"}

_rotations = {"rx": "rx", "ry": "ry", "rz": "rz"}

_two_qubit_gates = {"cx": "cnot", "cz": "cz", "swap": "swap"}
Expand All @@ -43,6 +45,8 @@ def _map_gate_name(gate: str) -> str:
return _adj_gates[gate]
elif gate in _measurements:
return _measurements[gate]
elif gate in _delays:
return _delays[gate]
elif gate in _rotations:
return _rotations[gate]
elif gate in _two_qubit_gates:
Expand Down Expand Up @@ -76,6 +80,27 @@ def test_fixture():
locals()[name] = _generate_one_qubit_fixture(gate)


def _generate_delay_gate_fixture(unit: str):
@pytest.fixture()
def test_fixture():
circuit = QuantumCircuit(1)
if unit == 'dt':
circuit.delay(1, 0, unit=unit)
else:
circuit.delay(0.5, 0, unit=unit)
return _map_gate_name('delay'), unit, circuit

return test_fixture


delay_tests = []
# Generate time param operation fixtures
for unit in {'s', 'ms', 'us', 'ns', 'ps', 'dt'}:
name = _fixture_name('delay_' + unit)
delay_tests.append(name)
locals()[name] = _generate_delay_gate_fixture(unit)


def _generate_rotation_fixture(gate: str):
@pytest.fixture()
def test_fixture():
Expand Down
21 changes: 21 additions & 0 deletions tests/test_qiskit_qir.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from test_circuits.basic_gates import (
single_op_tests,
adj_op_tests,
delay_tests,
rotation_tests,
double_op_tests,
triple_op_tests,
Expand Down Expand Up @@ -112,6 +113,7 @@ def test_adj_gates(circuit_name, request):
def test_rotation_gates(circuit_name, request):
qir_op, circuit = request.getfixturevalue(circuit_name)
generated_qir = str(to_qir_module(circuit)[0]).splitlines()
print(generated_qir)
test_utils.check_attributes(generated_qir, 1, 0)
func = test_utils.get_entry_point_body(generated_qir)
assert func[0] == test_utils.initialize_call_string()
Expand All @@ -120,6 +122,25 @@ def test_rotation_gates(circuit_name, request):
assert len(func) == 3


@pytest.mark.parametrize("circuit_name", delay_tests)
def test_delay_gate(circuit_name, request):
qir_op, unit, circuit = request.getfixturevalue(circuit_name)
generated_qir = str(to_qir_module(circuit)[0]).splitlines()
print(circuit)
print(generated_qir)
test_utils.check_attributes(generated_qir, 1, 0)
func = test_utils.get_entry_point_body(generated_qir)
assert func[0] == test_utils.initialize_call_string()
if unit == 'dt':
assert func[1] == test_utils.rotation_call_string(qir_op, 1, 0)
else:
multipliers = {"s": 1e6, "ms": 1e3, "us": 1, "ns": 1e-3, "ps": 1e-6}
duration = 0.5 * multipliers[unit]
assert func[1] == test_utils.rotation_call_string(qir_op, duration, 0)
assert func[2] == test_utils.return_string()
assert len(func) == 3


@pytest.mark.parametrize("circuit_name", double_op_tests)
def test_double_qubit_gates(circuit_name, request):
qir_op, circuit = request.getfixturevalue(circuit_name)
Expand Down

0 comments on commit 96734a9

Please sign in to comment.