qml.workflow.get_transform_program¶
- get_transform_program(qnode, level=None, gradient_fn='unset')[source]¶
Extract a transform program at a designated level.
- Parameters
qnode (QNode) – the qnode to get the transform program for.
level (None, str, int, slice) –
An indication of what transforms to use from the full program.
None
: use the full transform programstr
: Acceptable keys are"user"
,"device"
,"top"
and"gradient"
int
: How many transforms to include, starting from the front of the programslice
: a slice to select out components of the transform program.
gradient_fn (None, str, TransformDispatcher) – The processed gradient fn for the workflow.
- Returns
the transform program corresponding to the requested level.
- Return type
Usage Details
The transforms are organized as:
where
transform1
is first applied to theQNode
followed bytransform2
. First, user transforms are run on the tapes, followed by the gradient expansion, followed by the device expansion. “Final” transforms, likeparam_shift
andmetric_tensor
, always occur at the end of the program, despite being part of user transforms. Note that when requesting a level by name (e.g. “gradient” or “device”), the preceding levels would be applied as well.dev = qml.device('default.qubit') @qml.metric_tensor # final transform @qml.transforms.merge_rotations # transform 2 @qml.transforms.cancel_inverses # transform 1 @qml.qnode(dev, diff_method="parameter-shift", shifts=np.pi / 4) def circuit(): return qml.expval(qml.Z(0))
By default, we get the full transform program. This can be manually specified by
level=None
.>>> qml.workflow.get_transform_program(circuit) TransformProgram(cancel_inverses, merge_rotations, _expand_metric_tensor, _expand_transform_param_shift, validate_device_wires, defer_measurements, decompose, validate_measurements, validate_observables, metric_tensor)
The
"user"
transforms are the ones manually applied to the qnode,cancel_inverses()
,merge_rotations()
andmetric_tensor()
.>>> qml.workflow.get_transform_program(circuit, level="user") TransformProgram(cancel_inverses, merge_rotations, _expand_metric_tensor, metric_tensor)
The
_expand_transform_param_shift
is the"gradient"
transform. This expands all trainable operations to a state where the parameter shift transform can operate on them. For example, it will decompose any parametrized templates into operators that have generators. Note howmetric_tensor
is still present at the very end of resulting program.>>> qml.workflow.get_transform_program(circuit, level="gradient") TransformProgram(cancel_inverses, merge_rotations, _expand_metric_tensor, _expand_transform_param_shift, metric_tensor)
"device"
is equivalent tolevel=None
and includes all transforms. Semantically, this usually corresponds to the circuits that will be sent to the device to execute.>>> qml.workflow.get_transform_program(circuit, level="device") TransformProgram(cancel_inverses, merge_rotations, _expand_transform_param_shift, validate_device_wires, defer_measurements, decompose, validate_measurements, validate_observables, metric_tensor)
"top"
and0
both return empty transform programs.>>> qml.workflow.get_transform_program(circuit, level="top") TransformProgram() >>> qml.workflow.get_transform_program(circuit, level=0) TransformProgram()
The
level
can also be any integer, corresponding to a number of transforms in the program.>>> qml.workflow.get_transform_program(circuit, level=2) TransformProgram(cancel_inverses, merge_rotations)
level
can also accept aslice
object to select out any arbitrary subset of the transform program. This allows you to select different starting transforms or strides. For example, you can skip the first transform or reverse the order:>>> qml.workflow.get_transform_program(circuit, level=slice(1,3)) TransformProgram(merge_rotations, _expand_transform_param_shift) >>> qml.workflow.get_transform_program(circuit, level=slice(None, None, -1)) TransformProgram(metric_tensor, validate_observables, validate_measurements, decompose, defer_measurements, validate_device_wires, _expand_transform_param_shift, _expand_metric_tensor, merge_rotations, cancel_inverses)
You can get creative and pick a single category of transforms as follows, excluding any preceding transforms (and the final transform if it exists):
>>> user_prog = qml.workflow.get_transform_program(circuit, level="user") >>> grad_prog = qml.workflow.get_transform_program(circuit, level="gradient") >>> dev_prog = qml.workflow.get_transform_program(circuit, level="device") >>> grad_prog[len(user_prog) - 1 : -1] TransformProgram(_expand_transform_param_shift) >>> dev_prog[len(grad_prog) - 1 : -1] TransformProgram(validate_device_wires, mid_circuit_measurements, decompose, validate_measurements, validate_observables)