qml.workflow.get_compile_pipeline¶
- get_compile_pipeline(qnode, level='device')[source]¶
Extract a compile pipeline at a designated level.
- Parameters:
qnode (QNode) – The QNode to get the compile pipeline for.
level (str, int, slice) –
An indication of what transforms to use from the full compile pipeline.
"top": Returns an empty compile pipeline."user": Retrieves a compile pipeline containing manually applied user transformations."gradient": Retrieves a compile pipeline that includes user transformations and any relevant gradient transformations."device": Retrieves the entire compile pipeline (user + gradient + device) that is used for execution.str: Can also accept a string corresponding to the name of a marker that was manually added to the compile pipeline.int: Can also accept an integer, corresponding to a number of transforms in the program.level=0corresponds to the start of the program.slice: Can also accept asliceobject to select an arbitrary subset of the compile pipeline.
- Returns:
the compile pipeline corresponding to the requested level.
- Return type:
- Raises:
ValueError – If a final transform is applied to the qnode with a level that goes deeper than the gradient level of the compile pipeline.
Example:
Consider this simple circuit,
dev = qml.device("default.qubit") @qml.transforms.merge_rotations @qml.transforms.cancel_inverses @qml.qnode(dev) def circuit(): qml.RX(1, wires=0) qml.H(0) qml.H(0) qml.RX(1, wires=0) return qml.expval(qml.Z(0))
We can retrieve the compile pipeline used during execution with,
>>> get_compile_pipeline(circuit)() # or level="device" CompilePipeline(cancel_inverses, merge_rotations, defer_measurements, decompose, device_resolve_dynamic_wires, validate_device_wires, validate_measurements, _conditional_broadcast_expand, no_sampling)
or use the
levelargument to inspect specific stages of the pipeline.>>> get_compile_pipeline(circuit, level="user")() CompilePipeline(cancel_inverses, merge_rotations)
Usage Details
Consider the circuit below which is loaded with user applied transforms, a checkpoint marker and uses the parameter-shift gradient method,
dev = qml.device("default.qubit") @qml.metric_tensor @qml.transforms.merge_rotations @qml.marker("checkpoint") @qml.transforms.cancel_inverses @qml.qnode(dev, diff_method="parameter-shift", gradient_kwargs={"shifts": np.pi / 4}) def circuit(x): qml.RX(x, wires=0) qml.H(0) qml.H(0) qml.RX(x, wires=0) return qml.expval(qml.Z(0))
By default, without specifying a
levelwe will get the full compile pipeline that is used during execution on this device. Note that this can also be retrieved by manually specifyinglevel="device",>>> get_compile_pipeline(circuit)(3.14) CompilePipeline(cancel_inverses, marker, merge_rotations, _expand_metric_tensor, metric_tensor, _expand_transform_param_shift, defer_measurements, decompose, device_resolve_dynamic_wires, validate_device_wires, validate_measurements, _conditional_broadcast_expand)
As can be seen above, this not only includes the two transforms we manually applied, but also a set of transforms used by the device in order to execute the circuit. The
"user"level will retrieve the portion of the compile pipeline that was manually applied by the user to the qnode,>>> get_compile_pipeline(circuit, level="user")(3.14) CompilePipeline(cancel_inverses, marker, merge_rotations, _expand_metric_tensor, metric_tensor)
The
"gradient"level builds on top of this to then add any relevant gradient transforms,>>> get_compile_pipeline(circuit, level="gradient")(3.14) CompilePipeline(cancel_inverses, marker, merge_rotations, _expand_metric_tensor, metric_tensor, _expand_transform_param_shift)
which in this case is
_expand_transform_param_shift, a transform that expands all trainable operations to a state where the parameter shift transform can operate on them.We can use
qml.markerto further subdivide our compile pipeline into stages,>>> get_compile_pipeline(circuit, level="checkpoint")(3.14) CompilePipeline(cancel_inverses)
If
"top"or0are specified, an empty compile pipeline will be returned,>>> get_compile_pipeline(circuit, level=0)(3.14) CompilePipeline() >>> get_compile_pipeline(circuit, level="top")(3.14) CompilePipeline()
Integer levels correspond to the number of transforms to retrieve from the compile pipeline,
>>> get_compile_pipeline(circuit, level=3)(3.14) CompilePipeline(cancel_inverses, marker, merge_rotations)
Slice levels enable you to extract a specific range of transformations in the compile pipeline. For example, we can retrieve the second to fourth transform by using a slice,
>>> get_compile_pipeline(circuit, level=slice(1,4))(3.14) CompilePipeline(marker, merge_rotations, _expand_metric_tensor)