Qiskit 0.14 release notes
0.14.0
Terra 0.11.0
Prelude
The 0.11.0 release includes several new features and bug fixes. The biggest change for this release is the addition of the pulse scheduler. This allows users to define their quantum program as a QuantumCircuit
and then map it to the underlying pulse instructions that will control the quantum hardware to implement the circuit.
New Features
-
Added 5 new commands to easily retrieve user-specific data from
BackendProperties
:gate_property
,gate_error
,gate_length
,qubit_property
,t1
,t2
,readout_error
andfrequency
. They return the specific values of backend properties. For example:from qiskit.test.mock import FakeOurense backend = FakeOurense() properties = backend.properties() gate_property = properties.gate_property('u1') gate_error = properties.gate_error('u1', 0) gate_length = properties.gate_length('u1', 0) qubit_0_property = properties.qubit_property(0) t1_time_0 = properties.t1(0) t2_time_0 = properties.t2(0) readout_error_0 = properties.readout_error(0) frequency_0 = properties.frequency(0)
-
Added method
Instruction.is_parameterized()
to check if an instruction object is parameterized. This method returnsTrue
if and only if instruction has aParameterExpression
orParameter
object for one of its params. -
Added a new analysis pass
Layout2qDistance
. This pass allows to “score” a layout selection, onceproperty_set['layout']
is set. The score will be the sum of distances for each two-qubit gate in the circuit, when they are not directly connected. This scoring does not consider direction in the coupling map. The lower the number, the better the layout selection is.For example, consider a linear coupling map
[0]--[2]--[1]
and the following circuit:qr = QuantumRegister(2, 'qr') circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1])
If the layout is
{qr[0]:0, qr[1]:1}
,Layout2qDistance
will setproperty_set['layout_score'] = 1
. If the layout is{qr[0]:0, qr[1]:2}
, then the result isproperty_set['layout_score'] = 0
. The lower the score, the better. -
Added
qiskit.QuantumCircuit.cnot
as an alias for thecx
method ofQuantumCircuit
. The namescnot
andcx
are often used interchangeably now the cx method can be called with either name. -
Added
qiskit.QuantumCircuit.toffoli
as an alias for theccx
method ofQuantumCircuit
. The namestoffoli
andccx
are often used interchangeably now the ccx method can be called with either name. -
Added
qiskit.QuantumCircuit.fredkin
as an alias for thecswap
method ofQuantumCircuit
. The namesfredkin
andcswap
are often used interchangeably now the cswap method can be called with either name. -
The
latex
output mode forqiskit.visualization.circuit_drawer()
and theqiskit.circuit.QuantumCircuit.draw()
method now has a mode to passthrough raw latex from gate labels and parameters. The syntax for doing this mirrors matplotlib’s mathtext mode syntax. Any portion of a label string between a pair of ‘$’ characters will be treated as raw latex and passed directly into the generated output latex. This can be leveraged to add more advanced formatting to circuit diagrams generated with the latex drawer.Prior to this release all gate labels were run through a utf8 -> latex conversion to make sure that the output latex would compile the string as expected. This is still what happens for all portions of a label outside the ‘$’ pair. Also if you want to use a dollar sign in your label make sure you escape it in the label string (ie
'\$'
).You can mix and match this passthrough with the utf8 -> latex conversion to create the exact label you want, for example:
from qiskit import circuit circ = circuit.QuantumCircuit(2) circ.h([0, 1]) circ.append(circuit.Gate(name='α_gate', num_qubits=1, params=[0]), [0]) circ.append(circuit.Gate(name='α_gate$_2$', num_qubits=1, params=[0]), [1]) circ.append(circuit.Gate(name='\$α\$_gate', num_qubits=1, params=[0]), [1]) circ.draw(output='latex')
will now render the first custom gate’s label as
α_gate
, the second will beα_gate
with a 2 subscript, and the last custom gate’s label will be$α$_gate
. -
Add
ControlledGate
class for representing controlled gates. Controlled gate instances are created with thecontrol(n)
method ofGate
objects wheren
represents the number of controls. The control qubits come before the controlled qubits in the new gate. For example:from qiskit import QuantumCircuit from qiskit.extensions import HGate hgate = HGate() circ = QuantumCircuit(4) circ.append(hgate.control(3), [0, 1, 2, 3]) print(circ)
generates:
q_0: |0>──■── │ q_1: |0>──■── │ q_2: |0>──■── ┌─┴─┐ q_3: |0>┤ H ├ └───┘
-
Allowed values of
meas_level
parameters and fields can now be a member from the IntEnum classqiskit.qobj.utils.MeasLevel
. This can be used when callingexecute
(or anywhere elsemeas_level
is specified) with a pulse experiment. For example:from qiskit import QuantumCircuit, transpile, schedule, execute from qiskit.test.mock import FakeOpenPulse2Q from qiskit.qobj.utils import MeasLevel, MeasReturnType backend = FakeOpenPulse2Q() qc = QuantumCircuit(2, 2) qc.h(0) qc.cx(0,1) qc_transpiled = transpile(qc, backend) sched = schedule(qc_transpiled, backend) execute(sched, backend, meas_level=MeasLevel.CLASSIFIED)
In this above example,
meas_level=MeasLevel.CLASSIFIED
andmeas_level=2
can be used interchangably now. -
A new layout selector based on constraint solving is included. CSPLayout models the problem of finding a layout as a constraint problem and uses recursive backtracking to solve it.
cmap16 = CouplingMap(FakeRueschlikon().configuration().coupling_map) qr = QuantumRegister(5, 'q') circuit = QuantumCircuit(qr) circuit.cx(qr[0], qr[1]) circuit.cx(qr[0], qr[2]) circuit.cx(qr[0], qr[3]) pm = PassManager(CSPLayout(cmap16)) circuit_after = pm.run(circuit) print(pm.property_set['layout'])
Layout({ 1: Qubit(QuantumRegister(5, 'q'), 1), 2: Qubit(QuantumRegister(5, 'q'), 0), 3: Qubit(QuantumRegister(5, 'q'), 3), 4: Qubit(QuantumRegister(5, 'q'), 4), 15: Qubit(QuantumRegister(5, 'q'), 2) })
The parameter
CSPLayout(...,strict_direction=True)
is more restrictive but it will guarantee there is no need of runningCXDirection
after.pm = PassManager(CSPLayout(cmap16, strict_direction=True)) circuit_after = pm.run(circuit) print(pm.property_set['layout'])
Layout({ 8: Qubit(QuantumRegister(5, 'q'), 4), 11: Qubit(QuantumRegister(5, 'q'), 3), 5: Qubit(QuantumRegister(5, 'q'), 1), 6: Qubit(QuantumRegister(5, 'q'), 0), 7: Qubit(QuantumRegister(5, 'q'), 2) })
If the constraint system is not solvable, the layout property is not set.
circuit.cx(qr[0], qr[4]) pm = PassManager(CSPLayout(cmap16)) circuit_after = pm.run(circuit) print(pm.property_set['layout'])
None
-
PulseBackendConfiguration (accessed normally as backend.configuration()) has been extended with useful methods to explore its data and the functionality that exists in PulseChannelSpec. PulseChannelSpec will be deprecated in the future. For example:
backend = provider.get_backend(backend_name) config = backend.configuration() q0_drive = config.drive(0) # or, DriveChannel(0) q0_meas = config.measure(0) # MeasureChannel(0) q0_acquire = config.acquire(0) # AcquireChannel(0) config.hamiltonian # Returns a dictionary with hamiltonian info config.sample_rate() # New method which returns 1 / dt
-
PulseDefaults
(accessed normally asbackend.defaults()
) has an attribute,circuit_instruction_map
which has the methods of CmdDef. The new circuit_instruction_map is anInstructionScheduleMap
object with three new functions beyond what CmdDef had:- qubit_instructions(qubits) returns the operations defined for the qubits
- assert_has(instruction, qubits) raises an error if the op isn’t defined
- remove(instruction, qubits) like pop, but doesn’t require parameters
There are some differences from the CmdDef:
__init__
takes no argumentscmds
andcmd_qubits
are deprecated and replaced withinstructions
andqubits_with_instruction
Example:
backend = provider.get_backend(backend_name) inst_map = backend.defaults().circuit_instruction_map qubit = inst_map.qubits_with_instruction('u3')[0] x_gate = inst_map.get('u3', qubit, P0=np.pi, P1=0, P2=np.pi) pulse_schedule = x_gate(DriveChannel(qubit))
-
A new kwarg parameter,
show_framechange_channels
to optionally disable displaying channels with only framechange instructions in pulse visualizations was added to theqiskit.visualization.pulse_drawer()
function andqiskit.pulse.Schedule.draw()
method. When this new kwarg is set toFalse
the output pulse schedule visualization will not include any channels that only include frame changes.For example:
from qiskit.pulse import * from qiskit.pulse import library as pulse_lib gp0 = pulse_lib.gaussian(duration=20, amp=1.0, sigma=1.0) sched = Schedule() channel_a = DriveChannel(0) channel_b = DriveChannel(1) sched += Play(gp0, channel_a) sched = sched.insert(60, ShiftPhase(-1.57, channel_a)) sched = sched.insert(30, ShiftPhase(-1.50, channel_b)) sched = sched.insert(70, ShiftPhase(1.50, channel_b)) sched.draw(show_framechange_channels=False)
-
A new utility function
qiskit.result.marginal_counts()
is added which allows marginalization of the counts over some indices of interest. This is useful when more qubits are measured than needed, and one wishes to get the observation counts for some subset of them only. -
When
passmanager.run(...)
is invoked with more than one circuit, the transpilation of these circuits will run in parallel. -
PassManagers can now be sliced to create a new PassManager containing a subset of passes using the square bracket operator. This allow running or drawing a portion of the PassManager for easier testing and visualization. For example let’s try to draw the first 3 passes of a PassManager pm, or run just the second pass on our circuit:
pm[0:4].draw() circuit2 = pm[1].run(circuit)
Also now, PassManagers can be created by adding two PassManagers or by directly adding a pass/list of passes to a PassManager.
pm = pm1[0] + pm2[1:3] pm += [setLayout, unroller]
-
A basic
scheduler
module has now been added to Qiskit. The scheduler schedules an input transpiledQuantumCircuit
into a pulseSchedule
. The scheduler accepts as input aSchedule
and either a pulseBackend
, or aCmdDef
which relates circuitInstruction
objects on specific qubits to pulse Schedules and ameas_map
which determines which measurements must occur together.Scheduling example:
from qiskit import QuantumCircuit, transpile, schedule from qiskit.test.mock import FakeOpenPulse2Q backend = FakeOpenPulse2Q() qc = QuantumCircuit(2, 2) qc.h(0) qc.cx(0,1) qc_transpiled = transpile(qc, backend) schedule(qc_transpiled, backend)
The scheduler currently supports two scheduling policies, as_late_as_possible (
alap
) and as_soon_as_possible (asap
), which respectively schedule pulse instructions to occur as late as possible or as soon as possible across qubits in a circuit. The scheduling policy may be selected with the input argumentmethod
, for example:schedule(qc_transpiled, backend, method='alap')
It is easy to use a pulse
Schedule
within aQuantumCircuit
by mapping it to a custom circuit instruction such as a gate which may be used in aQuantumCircuit
. To do this, first, define the custom gate and then add an entry into theCmdDef
for the gate, for each qubit that the gate will be applied to. The gate can then be used in theQuantumCircuit
. At scheduling time the gate will be mapped to the underlying pulse schedule. Using this technique allows easy integration with preexisting qiskit modules such as Ignis.For example:
from qiskit import pulse, circuit, schedule from qiskit.pulse import pulse_lib custom_cmd_def = pulse.CmdDef() # create custom gate custom_gate = circuit.Gate(name='custom_gate', num_qubits=1, params=[]) # define schedule for custom gate custom_schedule = pulse.Schedule() custom_schedule += pulse_lib.gaussian(20, 1.0, 10)(pulse.DriveChannel) # add schedule to custom gate with same name custom_cmd_def.add('custom_gate', (0,), custom_schedule) # use custom gate in a circuit custom_qc = circuit.QuantumCircuit(1) custom_qc.append(custom_gate, qargs=[0]) # schedule the custom gate schedule(custom_qc, cmd_def=custom_cmd_def, meas_map=[[0]])
Known Issues
- The feature for transpiling in parallel when
passmanager.run(...)
is invoked with more than one circuit is not supported under Windows. See #2988 for more details.
Upgrade Notes
- The
qiskit.pulse.channels.SystemTopology
class was used as a helper class forPulseChannelSpec
. It has been removed since with the deprecation ofPulseChannelSpec
and changes toBackendConfiguration
make it unnecessary. - The previously deprecated representation of qubits and classical bits as tuple, which was deprecated in the 0.9 release, has been removed. The use of
Qubit
andClbit
objects is the new way to represent qubits and classical bits. - The previously deprecated representation of the basis set as single string has been removed. A list of strings is the new preferred way.
- The method
BaseModel.as_dict
, which was deprecated in the 0.9 release, has been removed in favor of the methodBaseModel.to_dict
. - In PulseDefaults (accessed normally as backend.defaults()),
qubit_freq_est
andmeas_freq_est
are now returned in Hz rather than GHz. This means the new return values are 1e9 * their previous value. - dill was added as a requirement. This is needed to enable running
passmanager.run()
in parallel for more than one circuit. - The previously deprecated gate
UBase
, which was deprecated in the 0.9 release, has been removed. The gateU3Gate
should be used instead. - The previously deprecated gate
CXBase
, which was deprecated in the 0.9 release, has been removed. The gateCnotGate
should be used instead. - The instruction
snapshot
used to implicitly convert thelabel
parameter to string. That conversion has been removed and an error is raised if a string is not provided. - The previously deprecated gate
U0Gate
, which was deprecated in the 0.9 release, has been removed. The gateIdGate
should be used instead to insert delays.
Deprecation Notes
-
The
qiskit.pulse.CmdDef
class has been deprecated. Instead you should use theqiskit.pulse.InstructionScheduleMap
. TheInstructionScheduleMap
object for a pulse enabled system can be accessed atbackend.defaults().instruction_schedules
. -
PulseChannelSpec
is being deprecated. UseBackendConfiguration
instead. The backend configuration is accessed normally asbackend.configuration()
. The config has been extended with most of the functionality of PulseChannelSpec, with some modifications as follows, where 0 is an exemplary qubit index:pulse_spec.drives[0] -> config.drive(0) pulse_spec.measures[0] -> config.measure(0) pulse_spec.acquires[0] -> config.acquire(0) pulse_spec.controls[0] -> config.control(0)
Now, if there is an attempt to get a channel for a qubit which does not exist for the device, a
BackendConfigurationError
will be raised with a helpful explanation.The methods
memoryslots
andregisterslots
of the PulseChannelSpec have not been migrated to the backend configuration. These classical resources are not restrained by the physical configuration of a backend system. Please instantiate them directly:pulse_spec.memoryslots[0] -> MemorySlot(0) pulse_spec.registerslots[0] -> RegisterSlot(0)
The
qubits
method is not migrated to backend configuration. The result ofqubits
can be built as such:[q for q in range(backend.configuration().n_qubits)]
-
Qubit
withinpulse.channels
has been deprecated. They should not be used. It is possible to obtain channel <=> qubit mappings through the BackendConfiguration (or backend.configuration()). -
The function
qiskit.visualization.circuit_drawer.qx_color_scheme()
has been deprecated. This function is no longer used internally and doesn’t reflect the current IBM QX style. If you were using this function to generate a style dict locally you must save the output from it and use that dictionary directly. -
The Exception
TranspilerAccessError
has been deprecated. An alternative functionTranspilerError
can be used instead to provide the same functionality. This alternative function provides the exact same functionality but with greater generality. -
Buffers in Pulse are deprecated. If a nonzero buffer is supplied, a warning will be issued with a reminder to use a Delay instead. Other options would include adding samples to a pulse instruction which are (0.+0.j) or setting the start time of the next pulse to
schedule.duration + buffer
. -
Passing in
sympy.Basic
,sympy.Expr
andsympy.Matrix
types as instruction parameters are deprecated and will be removed in a future release. You’ll need to convert the input to one of the supported types which are:int
float
complex
str
np.ndarray
Bug Fixes
- The Collect2qBlocks and CommutationAnalysis passes in the transpiler had been unable to process circuits containing Parameterized gates, preventing Parameterized circuits from being transpiled at optimization_level 2 or above. These passes have been corrected to treat Parameterized gates as opaque.
- The align_measures function had an issue where Measure stimulus pulses weren’t properly aligned with Acquire pulses, resulting in an error. This has been fixed.
- Uses of
numpy.random.seed
have been removed so that calls of qiskit functions do not affect results of future calls tonumpy.random
- Fixed race condition occurring in the job monitor when
job.queue_position()
returnsNone
.None
is a valid return fromjob.queue_position()
. - Backend support for
memory=True
now checked when that kwarg is passed.QiskitError
results if not supported. - When transpiling without a coupling map, there were no check in the amount of qubits of the circuit to transpile. Now the transpile process checks that the backend has enough qubits to allocate the circuit.
Other Notes
- The
qiskit.result.marginal_counts()
function replaces a similar utility function in qiskit-ignisqiskit.ignis.verification.tomography.marginal_counts()
, which will be deprecated in a future qiskit-ignis release. - All sympy parameter output type support have been been removed (or deprecated as noted) from qiskit-terra. This includes sympy type parameters in
QuantumCircuit
objects, qasm ast nodes, orQobj
objects.
Aer 0.3
No Change
Ignis 0.2
No Change
Aqua 0.6
No Change
IBM Q Provider 0.4
Prelude
The 0.4.0 release is the first release that makes use of all the features of the new IBM Q API. In particular, the IBMQJob
class has been revamped in order to be able to retrieve more information from IBM Q, and a Job Manager class has been added for allowing a higher-level and more seamless usage of large or complex jobs. If you have not upgraded from the legacy IBM Q Experience or QConsole yet, please ensure to revisit the release notes for IBM Q Provider 0.3 (Qiskit 0.11) for more details on how to make the transition. The legacy accounts will no longer be supported as of this release.
New Features
Job modifications
The IBMQJob
class has been revised, and now mimics more closely to the contents of a remote job along with new features:
- You can now assign a name to a job, by specifying
IBMQBackend.run(..., job_name='...')
when submitting a job. This name can be retrieved viaIBMQJob.name()
and can be used for filtering. - Jobs can now be shared with other users at different levels (global, per hub, group or project) via an optional
job_share_level
parameter when submitting the job. IBMQJob
instances now have more attributes, reflecting the contents of the remote IBM Q jobs. This implies that new attributes introduced by the IBM Q API will automatically and immediately be available for use (for example,job.new_api_attribute
). The new attributes will be promoted to methods when they are considered stable (for example,job.name()
)..error_message()
returns more information on why a job failed..queue_position()
accepts arefresh
parameter for forcing an update..result()
accepts an optionalpartial
parameter, for returning partial results, if any, of jobs that failed. Be aware thatResult
methods, such asget_counts()
will raise an exception if applied on experiments that failed.
Please note that the changes include some low-level modifications of the class. If you were creating the instances manually, note that:
- the signature of the constructor has changed to account for the new features.
- the
.submit()
method can no longer be called directly, and jobs are expected to be submitted either via the synchronousIBMQBackend.run()
or via the Job Manager.
Job Manager
A new Job Manager (IBMQJobManager
) has been introduced, as a higher-level mechanism for handling jobs composed of multiple circuits or pulse schedules. The Job Manager aims to provide a transparent interface, intelligently splitting the input into efficient units of work and taking full advantage of the different components. It will be expanded on upcoming versions, and become the recommended entry point for job submission.
Its .run()
method receives a list of circuits or pulse schedules, and returns a ManagedJobSet instance
, which can then be used to track the statuses and results of these jobs. For example:
from qiskit.providers.ibmq.managed import IBMQJobManager
from qiskit.circuit.random import random_circuit
from qiskit import IBMQ
from qiskit.compiler import transpile
provider = IBMQ.load_account()
backend = provider.backends.ibmq_ourense
circs = []
for _ in range(1000000):
circs.append(random_circuit(2, 2))
transpile(circs, backend=backend)
# Farm out the jobs.
jm = IBMQJobManager()
job_set = jm.run(circs, backend=backend, name='foo')
job_set.statuses() # Gives a list of job statuses
job_set.report() # Prints detailed job information
results = job_set.results()
counts = results.get_counts(5) # Returns data for experiment 5
provider.backends modifications
The provider.backends
member, which was previously a function that returned a list of backends, has been promoted to a service. This implies that it can be used both in the previous way, as a .backends()
method, and also as a .backends
attribute with expanded capabilities:
-
it contains the existing backends from that provider as attributes, which can be used for autocompletion. For example:
my_backend = provider.get_backend('ibmq_qasm_simulator')
is equivalent to:
my_backend = provider.backends.ibmq_qasm_simulator
-
the
provider.backends.jobs()
andprovider.backends.retrieve_job()
methods can be used for retrieving provider-wide jobs.
Other changes
- The
backend.properties()
function now accepts an optionaldatetime
parameter. If specified, the function returns the backend properties closest to, but older than, the specified datetime filter. - Some
warnings
have been toned down tologger.warning
messages.