qml.lie_closure¶
- lie_closure(generators, *, max_iterations=10000, verbose=False, pauli=False, matrix=False, tol=None)[source]¶
Compute the (dynamical) Lie algebra from a set of generators.
The Lie closure, pronounced “Lee” closure, is a way to compute the so-called dynamical Lie algebra (DLA) of a set of generators \(\mathcal{G} = \{G_1, .. , G_N\}\). For such generators, one computes all nested commutators \([G_i, [G_j, .., [G_k, G_\ell]]]\) until no new operators are generated from commutation. All these operators together form the DLA, see e.g. section IIB of arXiv:2308.01432.
- Parameters:
generators (Iterable[Union[PauliWord, PauliSentence, Operator, TensorLike]]) – generating set for which to compute the Lie closure.
max_iterations (int) – maximum depth of nested commutators to consider. Default is
10000.verbose (bool) – whether to print out progress updates during Lie closure calculation. Default is
False.pauli (bool) – Indicates whether it is assumed that
PauliSentenceorPauliWordinstances are input and returned. This can help with performance to avoid unnecessary conversions toOperatorand vice versa. Default isFalse.matrix (bool) – Whether or not matrix representations should be used and returned in the Lie closure computation. This can help speed up the computation when using sums of Paulis with many terms. Default is
False.tol (float) – Numerical tolerance for the linear independence check used in
PauliVSpace.
- Returns:
A basis of either
PauliSentence,Operator, ornp.ndarrayinstances that is closed under commutators (Lie closure).- Return type:
Union[list[
PauliSentence], list[Operator], np.ndarray]
See also
structure_constants(),center(),PauliVSpace, Demo: Introduction to Dynamical Lie Algebras for quantum practitionersExample
>>> from pennylane import X, Y, Z >>> ops = [X(0) @ X(1), Z(0), Z(1)] >>> dla = qml.lie_closure(ops)
Let us walk through what happens in this simple example of computing the Lie closure of these generators (the transverse field Ising model on two qubits). A first round of commutators between all elements yields:
>>> qml.commutator(X(0) @ X(1), Z(0)) -2j * (Y(0) @ X(1)) >>> qml.commutator(X(0) @ X(1), Z(1)) -2j * (X(0) @ Y(1))
A next round of commutators between all elements further yields the new operator
Y(0) @ Y(1).>>> qml.commutator(X(0) @ Y(1), Z(0)) -2j * (Y(0) @ Y(1))
After that, no new operators emerge from taking nested commutators and we have the resulting DLA. This can be done in short via
lie_closureas follows.>>> ops = [X(0) @ X(1), Z(0), Z(1)] >>> dla = qml.lie_closure(ops) >>> dla [X(0) @ X(1), Z(0), Z(1), -1.0 * (Y(0) @ X(1)), -1.0 * (X(0) @ Y(1)), Y(0) @ Y(1)]
Note that we normalize by removing the factors of \(2i\), though minus signs are left intact.
Usage Details
Note that by default,
lie_closurereturns PennyLane operators. Internally we use the more efficient representation in terms ofPauliSentenceby making use of theop.pauli_repattribute of operators composed of Pauli operators. If desired, this format can be returned by using the keywordpauli=True. In that case, the input is also assumed to be aPauliSentenceinstance.>>> ops = [ ... PauliSentence({PauliWord({0: "X", 1: "X"}): 1.}), ... PauliSentence({PauliWord({0: "Z"}): 1.}), ... PauliSentence({PauliWord({1: "Z"}): 1.}), ... ] >>> dla = qml.lie_closure(ops, pauli=True) >>> dla [1.0 * X(0) @ X(1), 1.0 * Z(0), 1.0 * Z(1), -1.0 * Y(0) @ X(1), -1.0 * X(0) @ Y(1), 1.0 * Y(0) @ Y(1)] >>> type(dla[0]) <class 'pennylane.pauli.pauli_arithmetic.PauliSentence'>
In the case of sums of Pauli operators with many terms, it is often faster to use the matrix representation of the operators rather than the semi-analytic
PauliSentenceorOperatorrepresentation. We can force this by using thematrixkeyword. The resultingdlais anp.ndarrayof dimension(dim_g, 2**n, 2**n), wheredim_gis the dimension of the DLA andnthe number of qubits.>>> dla = qml.lie_closure(ops, matrix=True) >>> dla.shape (6, 4, 4)
You can retrieve a semi-analytic representation again by using
pauli_decompose().>>> dla_ops = [qml.pauli_decompose(op) for op in dla] >>> dla_ops [1.0 * (X(0) @ X(1)), 1.0 * (Z(0) @ I(1)), 1.0 * (I(0) @ Z(1)), 1.0 * (Y(0) @ X(1)), 1.0 * (X(0) @ Y(1)), 1.0 * (Y(0) @ Y(1))]