:orphan:
-
Added method
qml.math.sqrt_matrix_sparse
to compute the square root of a sparse Hermitian matrix. (#6976) -
Added a class
qml.capture.transforms.MergeRotationsInterpreter
that merges rotation operators following the same API asqml.transforms.optimization.merge_rotations
when experimental program capture is enabled. (#6957) -
qml.defer_measurements
can now be used with program capture enabled. Programs transformed byqml.defer_measurements
can be executed ondefault.qubit
. (#6838) (#6937) (#6961)Using
qml.defer_measurements
with program capture enables many new features, including:- Significantly richer variety of classical processing on mid-circuit measurement values.
- Using mid-circuit measurement values as gate parameters.
Functions such as the following can now be captured:
import jax.numpy as jnp qml.capture.enable() def f(x): m0 = qml.measure(0) m1 = qml.measure(0) a = jnp.sin(0.5 * jnp.pi * m0) phi = a - (m1 + 1) ** 4 qml.s_prod(x, qml.RZ(phi, 0)) return qml.expval(qml.Z(0))
-
Added class
qml.capture.transforms.UnitaryToRotInterpreter
that decomposesqml.QubitUnitary
operators following the same API asqml.transforms.unitary_to_rot
when experimental program capture is enabled. (#6916) (#6977) -
qml.lie_closure
now accepts and outputs matrix inputs using thematrix
keyword. Also addedqml.pauli.trace_inner_product
that can handle batches of dense matrices. (#6811) -
qml.structure_constants
now accepts and outputs matrix inputs using thematrix
keyword. (#6861)
-
Dispatch the linear algebra methods of
scipy
backend toscipy.sparse.linalg
explicitly. Nowqml.math
can correctly handle sparse matrices. (#6947) -
Added a class
qml.capture.transforms.MergeAmplitudeEmbedding
that mergesqml.AmplitudeEmbedding
operators following the same API asqml.transforms.merge_amplitude_embedding
when experimental program capture is enabled. (#6925) -
default.qubit
now supports the sparse matrices to be applied to the state vector. Specifically,QubitUnitary
initialized with a sparse matrix can now be applied to the state vector in thedefault.qubit
device. (#6883) -
merge_rotations
now correctly simplifies mergedqml.Rot
operators whose angles yield the identity operator. (#7011) -
Bump
rng_salt
tov0.40.0
. (#6854) -
qml.gradients.hadamard_grad
can now differentiate anything with a generator, and can accept circuits with non-commuting measurements. (#6928) -
Controlled
operators now have a full implementation ofsparse_matrix
that supportswire_order
configuration. (#6994) -
The
qml.measurements.NullMeasurement
measurement process is added to allow for profiling problems without the overheads associated with performing measurements. (#6989) -
pauli_rep
property is now accessible forAdjoint
operator when there is a Pauli representation. (#6871) -
qml.SWAP
now has sparse representation. (#6965) -
A
Lattice
class and agenerate_lattice
method is added to theqml.ftqc
module. Thegenerate_lattice
method is to generate 1D, 2D, 3D grid graphs with the given geometric parameters. (#6958) -
qml.QubitUnitary
now accepts sparse CSR matrices (fromscipy.sparse
). This allows efficient representation of large unitaries with mostly zero entries. Note that sparse unitaries are still in early development and may not support all features of their dense counterparts. (#6889) (#6986)>>> import numpy as np >>> import pennylane as qml >>> import scipy as sp >>> U_dense = np.eye(4) # 2-wire identity >>> U_sparse = sp.sparse.csr_matrix(U_dense) >>> op = qml.QubitUnitary(U_sparse, wires=[0, 1]) >>> print(op.matrix()) <Compressed Sparse Row sparse matrix of dtype 'float64' with 4 stored elements and shape (4, 4)> Coords Values (0, 0) 1.0 (1, 1) 1.0 (2, 2) 1.0 (3, 3) 1.0 >>> op.matrix().toarray() array([[1., 0., 0., 0.], [0., 1., 0., 0.], [0., 0., 1., 0.], [0., 0., 0., 1.]])
-
Add a decomposition for multi-controlled global phases into a one-less-controlled phase shift. (#6936)
-
qml.StatePrep
now accepts sparse state vectors. Users can createStatePrep
usingscipy.sparse.csr_matrix
. Note that non-zeropad_with
is forbidden. (#6863)>>> import scipy as sp >>> init_state = sp.sparse.csr_matrix([0, 0, 1, 0]) >>> qsv_op = qml.StatePrep(init_state, wires=[1, 2]) >>> wire_order = [0, 1, 2] >>> ket = qsv_op.state_vector(wire_order=wire_order) >>> print(ket) <Compressed Sparse Row sparse matrix of dtype 'float64' with 1 stored elements and shape (1, 8)> Coords Values (0, 2) 1.0
-
A
RuntimeWarning
is now raised byqml.QNode
andqml.execute
if executing JAX workflows and the installed version of JAX is greater than0.4.28
. (#6864) -
Added the
qml.workflow.construct_execution_config(qnode)(*args,**kwargs)
helper function. Users can now construct the execution configuration from a particularQNode
instance. (#6901)@qml.qnode(qml.device("default.qubit", wires=1)) def circuit(x): qml.RX(x, 0) return qml.expval(qml.Z(0))
>>> config = qml.workflow.construct_execution_config(circuit)(1) >>> pprint.pprint(config) ExecutionConfig(grad_on_execution=False, use_device_gradient=True, use_device_jacobian_product=False, gradient_method='backprop', gradient_keyword_arguments={}, device_options={'max_workers': None, 'prng_key': None, 'rng': Generator(PCG64) at 0x15F6BB680}, interface=<Interface.NUMPY: 'numpy'>, derivative_order=1, mcm_config=MCMConfig(mcm_method=None, postselect_mode=None), convert_to_numpy=True)
-
QNode
objects now have anupdate
method that allows for re-configuring settings likediff_method
,mcm_method
, and more. This allows for easier on-the-fly adjustments to workflows. Any arguments not specified will retain their original value. (#6803)After constructing a
QNode
,import pennylane as qml @qml.qnode(device=qml.device("default.qubit")) def circuit(): qml.H(0) qml.CNOT([0,1]) return qml.probs()
its settings can be modified with
update
, which returns a newQNode
object. Here is an example of updating a QNode'sdiff_method
:>>> print(circuit.diff_method) best >>> new_circuit = circuit.update(diff_method="parameter-shift") >>> print(new_circuit.diff_method) 'parameter-shift'
-
Devices can now configure whether or not ML framework data is sent to them via an
ExecutionConfig.convert_to_numpy
parameter. End-to-end jitting ondefault.qubit
is used if the user specified ajax.random.PRNGKey
as a seed. (#6899) (#6788) (#6869) -
The coefficients of observables now have improved differentiability. (#6598)
-
An empty basis set in
qml.compile
is now recognized as valid, resulting in decomposition of all operators that can be decomposed. (#6821) -
An informative error is raised when a
QNode
withdiff_method=None
is differentiated. (#6770) -
qml.ops.sk_decomposition
has been improved to produce less gates for certain edge cases. This greatly impacts the performance ofqml.clifford_t_decomposition
, which should now give less extraneousqml.T
gates. (#6855) -
qml.gradients.finite_diff_jvp
has been added to compute the jvp of an arbitrary numeric function. (#6853) -
With program capture enabled,
QNode
's can now be differentiated withdiff_method="finite-diff"
. (#6853) -
The requested
diff_method
is now validated when program capture is enabled. (#6852) -
The
qml.clifford_t_decomposition
has been improved to use less gates when decomposingqml.PhaseShift
. (#6842) -
qml.qchem.taper
now handles wire ordering for the tapered observables more robustly. (#6954) -
A
ParametrizedMidMeasure
class is added to represent a mid-circuit measurement in an arbitrary measurement basis in the XY, YZ or ZX plane. SubclassesXMidMeasureMP
andYMidMeasureMP
represent X-basis and Y-basis measurements. These classes are part of the experimentalftqc
module. (#6938) (#6953) -
A
diagonalize_mcms
transform is added that diagonalizes anyParametrizedMidMeasure
, for devices that only natively support mid-circuit measurements in the computational basis. (#6938) -
Measurement functions
measure_x
,measure_y
andmeasure_arbitrary_basis
are added in the experimentalftqc
module. These functions apply a mid-circuit measurement and return aMeasurementValue
. They are analogous toqml.measure
for the computational basis, but instead measure in the X-basis, Y-basis, or an arbitrary basis, respectively. Functionqml.ftqc.measure_z
is also added as an alias forqml.measure
. (#6953) -
null.qubit
can now execute jaxpr. (#6924)
-
Traditional tape transforms in PennyLane can be automatically converted to work with program capture enabled. (#6922)
As an example, here is a custom tape transform, working with capture enabled, that shifts every
qml.RX
gate to the end of the circuit:qml.capture.enable() @qml.transform def shift_rx_to_end(tape): """Transform that moves all RX gates to the end of the operations list.""" new_ops, rxs = [], [] for op in tape.operations: if isinstance(op, qml.RX): rxs.append(op) else: new_ops.append(op) operations = new_ops + rxs new_tape = tape.copy(operations=operations) return [new_tape], lambda res: res[0]
A requirement for tape transforms to be compatible with program capture is to further decorate QNodes with the experimental
qml.capture.expand_plxpr_transforms
decorator.@qml.capture.expand_plxpr_transforms @shift_rx_to_end @qml.qnode(qml.device("default.qubit", wires=1)) def circuit(): qml.RX(0.1, wires=0) qml.H(wires=0) return qml.state()
>>> print(qml.draw(circuit)()) 0: ──H──RX(0.10)─┤ State
There are some exceptions to getting tape transforms to work with capture enabled:
- Transforms that return multiple tapes cannot be converted.
- Transforms that return non-trivial post-processing functions cannot be converted.
- Transforms will fail to execute if the transformed quantum function or QNode contains:
qml.cond
with dynamic parameters as predicates.qml.for_loop
with dynamic parameters forstart
,stop
, orstep
.qml.while_loop
.
-
Device.jaxpr_jvp
has been added to the device API to allow the definition of device derivatives when using program capture to jaxpr. (#7019) -
Device-provided derivatives are integrated into the program capture pipeline.
diff_method="adjoint"
can now be used withdefault.qubit
when capture is enabled. (#7019) -
The
qml.transforms.single_qubit_fusion
quantum transform can now be applied with program capture enabled. (#6945) (#7020) -
Added class
qml.capture.transforms.CommuteControlledInterpreter
that moves commuting gates past control and target qubits of controlled operations when experimental program capture is enabled. It follows the same API asqml.transforms.commute_controlled
. (#6946) -
qml.QNode
can now cache plxpr. When executing aQNode
for the first time, its plxpr representation will be cached based on the abstract evaluation of the arguments. Later executions that have arguments with the same shapes and data types will be able to use this cached plxpr instead of capturing the program again. (#6923) -
qml.QNode
now accepts astatic_argnums
argument. This argument can be used to indicate any arguments that should be considered static when capturing the quantum program. (#6923) -
A new, experimental
Operator
method calledcompute_qfunc_decomposition
has been added to represent decompositions with structure (e.g., control flow). This method is only used when capture is enabled withqml.capture.enable()
. (#6859) (#6881) (#7022) (#6917) -
Python control flow (
if/else
,for
,while
) is now supported when program capture is enabled by settingautograph=True
at the QNode level. (#6837)qml.capture.enable() dev = qml.device("default.qubit", wires=[0, 1, 2]) @qml.qnode(dev, autograph=True) def circuit(num_loops: int): for i in range(num_loops): if i % 2 == 0: qml.H(i) else: qml.RX(1,i) return qml.state()
>>> print(qml.draw(circuit)(num_loops=3)) 0: ──H────────┤ State 1: ──RX(1.00)─┤ State 2: ──H────────┤ State >>> circuit(3) Array([0.43879125+0.j , 0.43879125+0.j , 0. -0.23971277j, 0. -0.23971277j, 0.43879125+0.j , 0.43879125+0.j , 0. -0.23971277j, 0. -0.23971277j], dtype=complex64)
-
The higher order primitives in program capture can now accept inputs with abstract shapes. (#6786)
-
The
PlxprInterpreter
classes can now handle creating dynamic arrays viajnp.ones
,jnp.zeros
,jnp.arange
, andjnp.full
. #6865) -
The qnode primitive now stores the
ExecutionConfig
instead ofqnode_kwargs
. (#6991) -
Device.eval_jaxpr
now accepts anexecution_config
keyword argument. (#6991) -
The adjoint jvp of a jaxpr can be computed using default.qubit tooling. (#6875)
-
A new
qml.capture.eval_jaxpr
function has been implemented. This is a variant ofjax.core.eval_jaxpr
that can handle the creation of arrays with dynamic shapes. (#7052)
-
pennylane.labs.dla.lie_closure_dense
is removed and integrated intoqml.lie_closure
using the newdense
keyword. (#6811) -
pennylane.labs.dla.structure_constants_dense
is removed and integrated intoqml.structure_constants
using the newmatrix
keyword. (#6861) -
ResourceOperator.resource_params
is changed to a property. (#6973)
-
num_diagonalizing_gates
is no longer accessible inqml.specs
orQuantumScript.specs
. The calculation of this quantity is extremely expensive, and the definition is ambiguous for non-commuting observables. (#7047) -
qml.gradients.gradient_transform.choose_trainable_params
has been renamed tochoose_trainable_param_indices
to better reflect what it actually does. (#6928) -
MultiControlledX
no longer accepts strings as control values. (#6835) -
The input argument
control_wires
ofMultiControlledX
has been removed. (#6832) (#6862) -
qml.execute
now has a collection of keyword-only arguments. (#6598) -
The
decomp_depth
argument in :func:~pennylane.transforms.set_decomposition
has been removed. (#6824) -
The
max_expansion
argument in :func:~pennylane.devices.preprocess.decompose
has been removed. (#6824) -
The
tape
andqtape
properties ofQNode
have been removed. Instead, use theqml.workflow.construct_tape
function. (#6825) -
The
gradient_fn
keyword argument toqml.execute
has been removed. Instead, it has been replaced withdiff_method
. (#6830) -
The
QNode.get_best_method
andQNode.best_method_str
methods have been removed. Instead, use theqml.workflow.get_best_diff_method
function. (#6823) -
The
output_dim
property ofqml.tape.QuantumScript
has been removed. Instead, use methodshape
ofQuantumScript
orMeasurementProcess
to get the same information. (#6829) -
Removed method
qsvt_legacy
along with its private helper_qsp_to_qsvt
(#6827)
-
Specifying
pipeline=None
withqml.compile
is now deprecated. A sequence of transforms should always be specified. (#7004) -
The
ControlledQubitUnitary
will stop acceptingQubitUnitary
objects as arguments as itsbase
. Instead, useqml.ctrl
to construct a controlledQubitUnitary
. A folllow-on PR fixed accidental double-queuing when usingqml.ctrl
withQubitUnitary
. (#6840) (#6926) -
The
control_wires
argument inqml.ControlledQubitUnitary
has been deprecated. Instead, use thewires
argument as the second positional argument. (#6839) -
The
mcm_method
keyword inqml.execute
has been deprecated. Instead, use themcm_method
andpostselect_mode
arguments. (#6807) -
Specifying gradient keyword arguments as any additional keyword argument to the qnode is deprecated and will be removed in v0.42. The gradient keyword arguments should be passed to the new keyword argument
gradient_kwargs
via an explicit dictionary. This change will improve qnode argument validation. (#6828) -
The
qml.gradients.hamiltonian_grad
function has been deprecated. This gradient recipe is not required with the new operator arithmetic system. (#6849) -
The
inner_transform_program
andconfig
keyword arguments inqml.execute
have been deprecated. If more detailed control over the execution is required, useqml.workflow.run
with these arguments instead. (#6822) (#6879) -
The property
MeasurementProcess.return_type
has been deprecated. If observable type checking is needed, please use directisinstance
; if other text information is needed, please use class name, or another internal temporary private member_shortname
. (#6841) (#6906) (#6910)
-
Add support to
CollectOpsandMeas
for handlingqnode
primitives. (#6922) -
Change some
scipy
imports from submodules to whole module to reduce memory footprint of importing pennylane. (#7040) -
Add
NotImplementedError
s forgrad
andjacobian
inCollectOpsandMeas
. (#7041) -
Quantum transform interpreters now perform argument validation and will no longer check if the equation in the
jaxpr
is a transform primitive. (#7023) -
qml.for_loop
andqml.while_loop
have been moved from thecompiler
module to a newcontrol_flow
module. (#7017) -
qml.capture.run_autograph
is now idempotent. This meansrun_autograph(fn) = run_autograph(run_autograph(fn))
. (#7001) -
Minor changes to
DQInterpreter
for speedups with program capture execution. (#6984) -
Globally silences
no-member
pylint issues from jax. (#6987) -
Remove
QNode.get_gradient_fn
from source code. (#6898) -
The source code has been updated use black 25.1.0. (#6897)
-
Improved the
InterfaceEnum
object to prevent direct comparisons tostr
objects. (#6877) -
Added a
QmlPrimitive
class that inheritsjax.core.Primitive
to a newqml.capture.custom_primitives
module. This class contains aprim_type
property so that we can differentiate between different sets of PennyLane primitives. Consequently,QmlPrimitive
is now used to define all PennyLane primitives. (#6847) -
The
RiemannianGradientOptimizer
has been updated to take advantage of newer features. (#6882) -
Use
keep_intermediate=True
flag to keep Catalyst's IR when testing. Also use a different way of testing to see if something was compiled. (#6990)
-
The code example in the docstring for
qml.PauliSentence
now properly copy-pastes. (#6949) -
The docstrings for
qml.unary_mapping
,qml.binary_mapping
,qml.christiansen_mapping
,qml.qchem.localize_normal_modes
, andqml.qchem.VibrationalPES
have been updated to include better code examples. (#6717) -
The docstrings for
qml.qchem.localize_normal_modes
andqml.qchem.VibrationalPES
have been updated to include examples that can be copied. (#6834) -
Fixed a typo in the code example for
qml.labs.dla.lie_closure_dense
. (#6858) -
The code example in the docstring for
qml.BasisRotation
was corrected by includingwire_order
in the call toqml.matrix
. (#6891) -
The docstring of
qml.noise.meas_eq
has been updated to make its functionality clearer. (#6920)
-
qml.transforms.single_qubit_fusion
andqml.transforms.cancel_inverses
now correctly handle mid-circuit measurements when experimental program capture is enabled. (#7020) -
qml.math.get_interface
now correctly extracts the"scipy"
interface if provided a list/array of sparse matrices. (#7015) -
qml.ops.Controlled.has_sparse_matrix
now provides the correct information by checking if the target operator has a sparse or dense matrix defined. (#7025) -
qml.capture.PlxprInterpreter
now flattens pytree arguments before evaluation. (#6975) -
qml.GlobalPhase.sparse_matrix
now correctly returns a sparse matrix of the same shape asmatrix
. (#6940) -
qml.expval
no longer silently casts to a real number when observable coefficients are imaginary. (#6939) -
Fixed
qml.wires.Wires
initialization to disallowWires
objects as wires labels. Now,Wires
is idempotent, e.g.Wires([Wires([0]), Wires([1])])==Wires([0, 1])
. (#6933) -
qml.capture.PlxprInterpreter
now correctly handles propagation of constants when interpreting higher-order primitives (#6913) -
qml.capture.PlxprInterpreter
now usesPrimitive.get_bind_params
to resolve primitive calling signatures before binding primitives. (#6913) -
The interface is now detected from the data in the circuit, not the arguments to the
QNode
. This allows interface data to be strictly passed as closure variables and still be detected. (#6892) -
BasisState
now casts its input to integers. (#6844) -
The
workflow.contstruct_batch
andworkflow.construct_tape
functions now correctly reflect themcm_method
passed to theQNode
, instead of assuming the method is alwaysdeferred
. (#6903) -
The
poly_to_angles
function has been improved to correctly work with different interfaces and no longer manipulate the input angles tensor internally. (#6979) -
The
QROM
template is upgraded to decompose more efficiently whenwork_wires
are not used. #6967) -
Processing mid-circuit measurements inside conditionals is not supported and previously resulted in unclear error messages or incorrect results. It is now explicitly not allowed, and raises an error when processing the tape. (#7027)
This release contains contributions from (in alphabetical order):
Guillermo Alonso, Utkarsh Azad, Henry Chang, Yushao Chen, Isaac De Vlugt, Diksha Dhawan, Lillian M.A. Frederiksen, Pietropaolo Frisoni, Marcus Gisslén, Korbinian Kottmann, Christina Lee, Joseph Lee, Mudit Pandey, Andrija Paurevic, Shuli Shu, David Wierichs