Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import warnings
import numbers
import multiprocessing as mp
from collections import OrderedDict
from collections import OrderedDict, defaultdict
import numpy as np
from qiskit.exceptions import QiskitError
from qiskit.util import is_main_process
Expand Down Expand Up @@ -167,6 +167,7 @@ def __init__(self, *regs, name=None, global_phase=0):
self._qubits = []
self._clbits = []
self._ancillas = []
self._calibrations = defaultdict(dict)
self.add_register(*regs)

# Parameter table tracks instructions with variable parameters.
Expand All @@ -189,6 +190,11 @@ def data(self):
"""
return QuantumCircuitData(self)

@property
def calibrations(self):
"""Return calibration dictionary."""
return dict(self._calibrations)

@data.setter
def data(self, data_input):
"""Sets the circuit data from a list of instructions and context.
Expand Down Expand Up @@ -2273,6 +2279,29 @@ def cz(self, control_qubit, target_qubit, *, label=None, ctrl_state=None,
return self.append(CZGate(label=label, ctrl_state=ctrl_state),
[control_qubit, target_qubit], [])

def add_calibration(self, gate, qubits, schedule, params=None):
"""Register a low-level, custom pulse definition for the given gate.

The custom pulse definition of a given gate is of the form
{'gate_name': {(qubits, params): schedule}}
Comment thread
SooluThomas marked this conversation as resolved.
Outdated

Args:
gate (Union[Gate, str]): Gate information.
Comment thread
SooluThomas marked this conversation as resolved.
qubits (Union[int, Tuple[int]]): List of qubits to be measured.
schedule (Schedule): Schedule information.
params (Optional[List[Union[float, Parameter]]]): A list of parameters.

Raises:
Exception: if the gate is of type string and params is None.
"""
if isinstance(gate, Gate):
self._calibrations[gate.name][(tuple(qubits), tuple(gate.params))] = schedule
Comment thread
lcapelluto marked this conversation as resolved.
elif isinstance(gate, str) and params is not None:
self._calibrations[gate][(tuple(qubits), tuple(params))] = schedule
elif isinstance(gate, str) and params is None:
raise Exception("Params for the gate {} is not "
"specified".format(gate))

Comment thread
SooluThomas marked this conversation as resolved.
Outdated

def _circuit_from_qasm(qasm):
# pylint: disable=cyclic-import
Expand Down
10 changes: 10 additions & 0 deletions qiskit/compiler/assemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ def assemble(experiments: Union[QuantumCircuit, List[QuantumCircuit], Schedule,

Raises:
QiskitError: if the input cannot be interpreted as either circuits or schedules
NotImplementedError: if circuit.calibrations is not empty.
"""
start_time = time()
experiments = experiments if isinstance(experiments, list) else [experiments]
Expand All @@ -142,6 +143,15 @@ def assemble(experiments: Union[QuantumCircuit, List[QuantumCircuit], Schedule,

# assemble either circuits or schedules
if all(isinstance(exp, QuantumCircuit) for exp in experiments):
# calibrate circuits to schedules (if any)
for exp in experiments:
if len(exp.calibrations) != 0:
# TODO: Do something here to schedule the circuits
# Raise an error - NotImplementedError" or try to schedule by adding
# cals to inst_map and call schedule.
# if scheduled, raise a warning - "Let the user know whats happening"
raise NotImplementedError

run_config = _parse_circuit_args(parameter_binds, **run_config_common_dict)

# If circuits are parameterized, bind parameters and remove from run_config
Expand Down
5 changes: 5 additions & 0 deletions qiskit/compiler/transpile.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ def callback_func(**kwargs):
_log_transpile_time(start_time, end_time)
return circuits

for circuit in circuits:
if len(circuit.calibrations) != 0:
# TODO: do something here
pass

if pass_manager is not None:
_check_conflicting_argument(optimization_level=optimization_level, basis_gates=basis_gates,
coupling_map=coupling_map, seed_transpiler=seed_transpiler,
Expand Down
26 changes: 25 additions & 1 deletion test/python/circuit/test_circuit_properties.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@

import unittest
import numpy as np
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, pulse
from qiskit.circuit.library import RXGate, RYGate
from qiskit.test import QiskitTestCase
from qiskit.circuit.exceptions import CircuitError
# pylint: disable=unused-import
Expand Down Expand Up @@ -616,6 +617,29 @@ def test_num_qubits_multiple_register_circuit(self):
circ = QuantumCircuit(q_reg1, q_reg2, q_reg3)
self.assertEqual(circ.num_qubits, 18)

def test_calibrations(self):
"""Check if the calibrations provided are added correctly."""
circ = QuantumCircuit(2)
circ.rx(3.14, 0)
circ.ry(1.57, 1)

with pulse.build() as q0_x180:
pulse.play(pulse.library.Gaussian(20, 1.0, 3.0), pulse.DriveChannel(0))
with pulse.build() as q1_y90:
pulse.play(pulse.library.Gaussian(20, -1.0, 3.0), pulse.DriveChannel(1))

# Add calibration
circ.add_calibration(RXGate(3.14), [0], q0_x180)
circ.add_calibration(RYGate(1.57), [1], q1_y90)

self.assertEqual(set(circ.calibrations.keys()), {'rx', 'ry'})
self.assertEqual(set(circ.calibrations['rx'].keys()), {((0,), (3.14,))})
self.assertEqual(set(circ.calibrations['ry'].keys()), {((1,), (1.57,))})
self.assertEqual(circ.calibrations['rx'][((0,), (3.14,))].instructions,
q0_x180.instructions)
self.assertEqual(circ.calibrations['ry'][((1,), (1.57,))].instructions,
q1_y90.instructions)

Comment thread
lcapelluto marked this conversation as resolved.

if __name__ == '__main__':
unittest.main()