mirror of https://github.com/Qiskit/qiskit.git
Add init qubits flag to qobj (#4432)
* Update schemas to include init_qubits config flag with default of true * Add init_qubits arg to execute and assemble, add tests * Execute should have init_qubits=None by default * Turns out default values are only added to the qobj if they are validated. This is not very robust, so I'll remove the default value for init_qubits * Update test/python/compiler/test_assembler.py Co-authored-by: Luciano Bello <luciano.bello@ibm.com> * Update test/python/compiler/test_assembler.py Co-authored-by: Luciano Bello <luciano.bello@ibm.com> * Respond to feedback: mention default value in docstring. Let init qubits be True by default. Break up the other tests, and make sure True shows up * Add a reno note Co-authored-by: Luciano Bello <luciano.bello@ibm.com> Co-authored-by: Thomas Alexander <talexander@ibm.com>
This commit is contained in:
parent
948671efd9
commit
6dbf9dd06b
|
@ -60,6 +60,7 @@ def assemble(experiments: Union[QuantumCircuit, List[QuantumCircuit], Schedule,
|
|||
rep_time: Optional[float] = None,
|
||||
parameter_binds: Optional[List[Dict[Parameter, float]]] = None,
|
||||
parametric_pulses: Optional[List[str]] = None,
|
||||
init_qubits: bool = True,
|
||||
**run_config: Dict) -> Qobj:
|
||||
"""Assemble a list of circuits or pulse schedules into a ``Qobj``.
|
||||
|
||||
|
@ -115,6 +116,8 @@ def assemble(experiments: Union[QuantumCircuit, List[QuantumCircuit], Schedule,
|
|||
Example::
|
||||
|
||||
['gaussian', 'constant']
|
||||
init_qubits: Whether to reset the qubits to the ground state for each shot.
|
||||
Default: ``True``.
|
||||
**run_config: Extra arguments used to configure the run (e.g., for Aer configurable
|
||||
backends). Refer to the backend documentation for details on these
|
||||
arguments.
|
||||
|
@ -130,7 +133,8 @@ def assemble(experiments: Union[QuantumCircuit, List[QuantumCircuit], Schedule,
|
|||
experiments = experiments if isinstance(experiments, list) else [experiments]
|
||||
qobj_id, qobj_header, run_config_common_dict = _parse_common_args(backend, qobj_id, qobj_header,
|
||||
shots, memory, max_credits,
|
||||
seed_simulator, **run_config)
|
||||
seed_simulator, init_qubits,
|
||||
**run_config)
|
||||
|
||||
# assemble either circuits or schedules
|
||||
if all(isinstance(exp, QuantumCircuit) for exp in experiments):
|
||||
|
@ -164,7 +168,7 @@ def assemble(experiments: Union[QuantumCircuit, List[QuantumCircuit], Schedule,
|
|||
|
||||
# TODO: rework to return a list of RunConfigs (one for each experiments), and a global one
|
||||
def _parse_common_args(backend, qobj_id, qobj_header, shots,
|
||||
memory, max_credits, seed_simulator,
|
||||
memory, max_credits, seed_simulator, init_qubits,
|
||||
**run_config):
|
||||
"""Resolve the various types of args allowed to the assemble() function through
|
||||
duck typing, overriding args, etc. Refer to the assemble() docstring for details on
|
||||
|
@ -221,6 +225,7 @@ def _parse_common_args(backend, qobj_id, qobj_header, shots,
|
|||
memory=memory,
|
||||
max_credits=max_credits,
|
||||
seed_simulator=seed_simulator,
|
||||
init_qubits=init_qubits,
|
||||
**run_config)
|
||||
|
||||
return qobj_id, qobj_header, run_config_dict
|
||||
|
|
|
@ -48,6 +48,7 @@ def execute(experiments, backend,
|
|||
meas_return=MeasReturnType.AVERAGE,
|
||||
memory_slots=None, memory_slot_size=100, rep_time=None, parameter_binds=None,
|
||||
schedule_circuit=False, inst_map=None, meas_map=None, scheduling_method=None,
|
||||
init_qubits=None,
|
||||
**run_config):
|
||||
"""Execute a list of :class:`qiskit.circuit.QuantumCircuit` or
|
||||
:class:`qiskit.pulse.Schedule` on a backend.
|
||||
|
@ -196,6 +197,9 @@ def execute(experiments, backend,
|
|||
scheduling_method (str or list(str)):
|
||||
Optionally specify a particular scheduling method.
|
||||
|
||||
init_qubits (bool): Whether to reset the qubits to the ground state for each shot.
|
||||
Default: ``True``.
|
||||
|
||||
run_config (dict):
|
||||
Extra arguments used to configure the run (e.g. for Aer configurable backends).
|
||||
Refer to the backend documentation for details on these arguments.
|
||||
|
@ -275,8 +279,8 @@ def execute(experiments, backend,
|
|||
rep_time=rep_time,
|
||||
parameter_binds=parameter_binds,
|
||||
backend=backend,
|
||||
**run_config
|
||||
)
|
||||
init_qubits=init_qubits,
|
||||
**run_config)
|
||||
|
||||
# executing the circuits on the backend and returning the job
|
||||
start_time = time()
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"meas_level": 2,
|
||||
"memory_slot_size": 1,
|
||||
"rep_time": 1000,
|
||||
"init_qubits": false,
|
||||
"qubit_lo_freq": [5.2,5.15,5.05],
|
||||
"meas_lo_freq": [6.9,6.8,6.7],
|
||||
"pulse_library": [
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
"backend_name": "ibmqx2"},
|
||||
"config": {
|
||||
"shots": 1024,
|
||||
"memory_slots": 1
|
||||
"memory_slots": 1,
|
||||
"init_qubits": true
|
||||
},
|
||||
"experiments": [
|
||||
{
|
||||
|
|
|
@ -802,6 +802,10 @@
|
|||
"description": "Total number of qubits used in this experiment.",
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"init_qubits": {
|
||||
"description": "Whether to initialize the qubits in the ground state before each shot.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"title": "Experiment level configuration",
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Users can request whether the backend inserts any initialization sequences
|
||||
at the start of each shot via ``assemble`` or ``execute``. By passing
|
||||
``init_qubits = False``, qubits will be uninitialized at the start of each
|
||||
experiment and between shots.
|
||||
|
||||
The default behavior is ``init_qubits = True``, which replicates the
|
||||
previously implict behavior: all qubits are assumed to be in the ground
|
||||
state at the start of each shot.
|
|
@ -39,17 +39,18 @@ from qiskit.validation.jsonschema import SchemaValidationError
|
|||
class TestCircuitAssembler(QiskitTestCase):
|
||||
"""Tests for assembling circuits to qobj."""
|
||||
|
||||
def setUp(self):
|
||||
qr = QuantumRegister(2, name='q')
|
||||
cr = ClassicalRegister(2, name='c')
|
||||
self.circ = QuantumCircuit(qr, cr, name='circ')
|
||||
self.circ.h(qr[0])
|
||||
self.circ.cx(qr[0], qr[1])
|
||||
self.circ.measure(qr, cr)
|
||||
|
||||
def test_assemble_single_circuit(self):
|
||||
"""Test assembling a single circuit.
|
||||
"""
|
||||
qr = QuantumRegister(2, name='q')
|
||||
cr = ClassicalRegister(2, name='c')
|
||||
circ = QuantumCircuit(qr, cr, name='circ')
|
||||
circ.h(qr[0])
|
||||
circ.cx(qr[0], qr[1])
|
||||
circ.measure(qr, cr)
|
||||
|
||||
qobj = assemble(circ, shots=2000, memory=True)
|
||||
qobj = assemble(self.circ, shots=2000, memory=True)
|
||||
validate_qobj_against_schema(qobj)
|
||||
|
||||
self.assertIsInstance(qobj, QasmQobj)
|
||||
|
@ -89,14 +90,7 @@ class TestCircuitAssembler(QiskitTestCase):
|
|||
def test_assemble_no_run_config(self):
|
||||
"""Test assembling with no run_config, relying on default.
|
||||
"""
|
||||
qr = QuantumRegister(2, name='q')
|
||||
qc = ClassicalRegister(2, name='c')
|
||||
circ = QuantumCircuit(qr, qc, name='circ')
|
||||
circ.h(qr[0])
|
||||
circ.cx(qr[0], qr[1])
|
||||
circ.measure(qr, qc)
|
||||
|
||||
qobj = assemble(circ)
|
||||
qobj = assemble(self.circ)
|
||||
validate_qobj_against_schema(qobj)
|
||||
|
||||
self.assertIsInstance(qobj, QasmQobj)
|
||||
|
@ -104,28 +98,15 @@ class TestCircuitAssembler(QiskitTestCase):
|
|||
|
||||
def test_shots_greater_than_max_shots(self):
|
||||
"""Test assembling with shots greater than max shots"""
|
||||
qr = QuantumRegister(2, name='q')
|
||||
qc = ClassicalRegister(2, name='c')
|
||||
circ = QuantumCircuit(qr, qc, name='circ')
|
||||
circ.h(qr[0])
|
||||
circ.cx(qr[0], qr[1])
|
||||
circ.measure(qr, qc)
|
||||
backend = FakeYorktown()
|
||||
|
||||
self.assertRaises(QiskitError, assemble, backend, shots=1024000)
|
||||
|
||||
def test_default_shots_greater_than_max_shots(self):
|
||||
"""Test assembling with default shots greater than max shots"""
|
||||
qr = QuantumRegister(2, name='q')
|
||||
qc = ClassicalRegister(2, name='c')
|
||||
circ = QuantumCircuit(qr, qc, name='circ')
|
||||
circ.h(qr[0])
|
||||
circ.cx(qr[0], qr[1])
|
||||
circ.measure(qr, qc)
|
||||
backend = FakeYorktown()
|
||||
backend._configuration.max_shots = 5
|
||||
|
||||
qobj = assemble(circ, backend)
|
||||
qobj = assemble(self.circ, backend)
|
||||
|
||||
validate_qobj_against_schema(qobj)
|
||||
|
||||
|
@ -345,12 +326,28 @@ class TestCircuitAssembler(QiskitTestCase):
|
|||
self.assertEqual(_qobj_inst_params(7, 0), [1, 0])
|
||||
self.assertEqual(_qobj_inst_params(8, 0), [2, 1])
|
||||
|
||||
def test_init_qubits_default(self):
|
||||
"""Check that the init_qubits=None assemble option is passed on to the qobj."""
|
||||
qobj = assemble(self.circ)
|
||||
self.assertEqual(qobj.config.init_qubits, True)
|
||||
|
||||
def test_init_qubits_true(self):
|
||||
"""Check that the init_qubits=True assemble option is passed on to the qobj."""
|
||||
qobj = assemble(self.circ, init_qubits=True)
|
||||
self.assertEqual(qobj.config.init_qubits, True)
|
||||
|
||||
def test_init_qubits_false(self):
|
||||
"""Check that the init_qubits=False assemble option is passed on to the qobj."""
|
||||
qobj = assemble(self.circ, init_qubits=False)
|
||||
self.assertEqual(qobj.config.init_qubits, False)
|
||||
|
||||
|
||||
class TestPulseAssembler(QiskitTestCase):
|
||||
"""Tests for assembling schedules to qobj."""
|
||||
|
||||
def setUp(self):
|
||||
self.backend_config = FakeOpenPulse2Q().configuration()
|
||||
self.backend = FakeOpenPulse2Q()
|
||||
self.backend_config = self.backend.configuration()
|
||||
|
||||
test_pulse = pulse.SamplePulse(
|
||||
samples=np.array([0.02739068, 0.05, 0.05, 0.05, 0.02739068], dtype=np.complex128),
|
||||
|
@ -630,15 +627,13 @@ class TestPulseAssembler(QiskitTestCase):
|
|||
|
||||
def test_assemble_with_delay(self):
|
||||
"""Test that delay instruction is ignored in assembly."""
|
||||
backend = FakeOpenPulse2Q()
|
||||
|
||||
orig_schedule = self.schedule
|
||||
with self.assertWarns(DeprecationWarning):
|
||||
delay_schedule = orig_schedule + pulse.Delay(10)(self.backend_config.drive(0))
|
||||
|
||||
orig_qobj = assemble(orig_schedule, backend)
|
||||
orig_qobj = assemble(orig_schedule, self.backend)
|
||||
validate_qobj_against_schema(orig_qobj)
|
||||
delay_qobj = assemble(delay_schedule, backend)
|
||||
delay_qobj = assemble(delay_schedule, self.backend)
|
||||
validate_qobj_against_schema(delay_qobj)
|
||||
|
||||
self.assertEqual(orig_qobj.experiments[0].to_dict(),
|
||||
|
@ -707,6 +702,21 @@ class TestPulseAssembler(QiskitTestCase):
|
|||
qobj_insts = qobj.experiments[0].instructions
|
||||
self.assertFalse(hasattr(qobj_insts[0], 'pulse_shape'))
|
||||
|
||||
def test_init_qubits_default(self):
|
||||
"""Check that the init_qubits=None assemble option is passed on to the qobj."""
|
||||
qobj = assemble(self.schedule, self.backend)
|
||||
self.assertEqual(qobj.config.init_qubits, True)
|
||||
|
||||
def test_init_qubits_true(self):
|
||||
"""Check that the init_qubits=True assemble option is passed on to the qobj."""
|
||||
qobj = assemble(self.schedule, self.backend, init_qubits=True)
|
||||
self.assertEqual(qobj.config.init_qubits, True)
|
||||
|
||||
def test_init_qubits_false(self):
|
||||
"""Check that the init_qubits=False assemble option is passed on to the qobj."""
|
||||
qobj = assemble(self.schedule, self.backend, init_qubits=False)
|
||||
self.assertEqual(qobj.config.init_qubits, False)
|
||||
|
||||
|
||||
class TestPulseAssemblerMissingKwargs(QiskitTestCase):
|
||||
"""Verify that errors are raised in case backend is not provided and kwargs are missing."""
|
||||
|
|
Loading…
Reference in New Issue