Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions demonstrations_v2/tutorial_liealgebra/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,22 @@
First, let us do a linear combination of :math:`\{iX, iY, iZ\}` with some real values and check unitarity after putting them in the exponent.
"""
import numpy as np
import pennylane as qml
import pennylane as qp
from pennylane import X, Y, Z

su2 = [1j * X(0), 1j * Y(0), 1j * Z(0)]

coeffs = [1., 2., 3.] # some real coefficients
exponent = qml.dot(coeffs, su2) # linear combination of operators
U = qml.math.expm(exponent.matrix()) # compute matrix exponent of lin. comb.
exponent = qp.dot(coeffs, su2) # linear combination of operators
U = qp.math.expm(exponent.matrix()) # compute matrix exponent of lin. comb.
print(np.allclose(U.conj().T @ U, np.eye(2))) # check that result is unitary UU* = 1

##############################################################################
# If we throw complex values in the mix, the resulting matrix is not unitary anymore.

coeffs = [1., 2.+ 1j, 3.] # some complex coefficients
exponent = qml.dot(coeffs, su2)
U = qml.math.expm(exponent.matrix())
exponent = qp.dot(coeffs, su2)
U = qp.math.expm(exponent.matrix())
print(np.allclose(U.conj().T @ U, np.eye(2))) # result is not unitary anymore

##############################################################################
Expand Down Expand Up @@ -158,7 +158,7 @@
#
# Let us do a quick example and compute the Lie closure of :math:`\{iX, iY\}` (more examples later).

print(qml.commutator(1j * X(0), 1j * Y(0)))
print(qp.commutator(1j * X(0), 1j * Y(0)))

##############################################################################
# We know that the commutator between :math:`iX` and :math:`iY` yields a new operator :math:`\propto iZ.`
Expand All @@ -168,15 +168,15 @@
list_ops = [1j * X(0), 1j * Y(0), 1j * Z(0)]
for op1 in list_ops:
for op2 in list_ops:
print(qml.commutator(op1, op2))
print(qp.commutator(op1, op2))

##############################################################################
# Since no new operators have been created we know the lie closure is complete and our dynamical Lie algebra
# is :math:`\langle\{iX, iY\}\rangle_\text{Lie} = \{iX, iY, iZ\}( = \mathfrak{su}(2)).`
#
# PennyLane provides some dedicated functionality for Lie algebras. We can compute the Lie closure of the generators using ``qml.lie_closure``.
# PennyLane provides some dedicated functionality for Lie algebras. We can compute the Lie closure of the generators using ``qp.lie_closure``.

dla = qml.lie_closure([X(0), Y(0)])
dla = qp.lie_closure([X(0), Y(0)])
dla

##############################################################################
Expand All @@ -187,14 +187,14 @@
# these :math:`X` and :math:`Y` rotations :math:`e^{-i \phi X}` and :math:`e^{-i \phi Y}.`
# For example, let us write a Pauli-Z rotation at non-trivial angle :math:`0.5` as a product of them.

U_target = qml.matrix(qml.RZ(-0.5, 0))
decomp = qml.ops.one_qubit_decomposition(U_target, 0, rotations="XYX")
U_target = qp.matrix(qp.RZ(-0.5, 0))
decomp = qp.ops.one_qubit_decomposition(U_target, 0, rotations="XYX")
print(decomp)

##############################################################################
# We can check that this is indeed a valid decomposition by computing the trace distance to the target.

U = qml.prod(*decomp).matrix()
U = qp.prod(*decomp).matrix()
print(1 - np.real(np.trace(U_target @ U))/2)

##############################################################################
Expand All @@ -215,10 +215,10 @@
generators = [1j * (X(0) @ X(1)), 1j * Z(0), 1j * Z(1)]

# collection of linearly independent basis vectors, automatically discards linearly dependent ones
dla = qml.pauli.PauliVSpace(generators, dtype=complex)
dla = qp.pauli.PauliVSpace(generators, dtype=complex)
for i, op1 in enumerate(generators):
for op2 in generators[i+1:]:
res = qml.commutator(op1, op2)/2
res = qp.commutator(op1, op2)/2
res = res.simplify() # ensures all products of scalars are executed
print(f"[{op1}, {op2}] = {res}")

Expand All @@ -234,7 +234,7 @@

for i, op1 in enumerate(dla.basis.copy()):
for op2 in dla.basis.copy()[i+1:]:
res = qml.commutator(op1, op2)/2
res = qp.commutator(op1, op2)/2
res = res.simplify()
print(f"[{op1}, {op2}] = {res}")

Expand All @@ -257,7 +257,7 @@
# We have constructed the DLA by hand to showcase the process. We can use the PennyLane function :func:`~lie_closure` for convenience.
# In that case, we omit the explicit use of the imgaginary factor.

dla2 = qml.lie_closure([X(0) @ X(1), Z(0), Z(1)])
dla2 = qp.lie_closure([X(0) @ X(1), Z(0), Z(1)])
for op in dla2:
print(op)

Expand All @@ -277,8 +277,8 @@ def IsingGenerators(n, bc="open"):
return gens

for n in range(2, 5):
open_ = qml.lie_closure(IsingGenerators(n, "open"))
periodic_ = qml.lie_closure(IsingGenerators(n, "periodic"))
open_ = qp.lie_closure(IsingGenerators(n, "open"))
periodic_ = qp.lie_closure(IsingGenerators(n, "periodic"))
print(f"Ising for n = {n}")
print(f"open: {len(open_)} = {n*(2*n-1)} = 2n * (2n - 1)/2")
print(f"open: {len(periodic_)} = {2*n*(2*n-1)} = 2 * 2n * (2n - 1)/2")
Expand Down Expand Up @@ -328,15 +328,15 @@ def IsingGenerators(n, bc="open"):
# Let us briefly verify this for a small example for ``n = 3`` qubits that readily generalizes to arbitrary sizes.

n = 3
H = qml.sum(*(P(i) @ P(i+1) for i in range(n-1) for P in [X, Y, Z]))
H = qp.sum(*(P(i) @ P(i+1) for i in range(n-1) for P in [X, Y, Z]))

SX = qml.sum(*(X(i) for i in range(n)))
SY = qml.sum(*(Y(i) for i in range(n)))
SZ = qml.sum(*(Z(i) for i in range(n)))
SX = qp.sum(*(X(i) for i in range(n)))
SY = qp.sum(*(Y(i) for i in range(n)))
SZ = qp.sum(*(Z(i) for i in range(n)))

print(qml.commutator(H, SX))
print(qml.commutator(H, SY))
print(qml.commutator(H, SZ))
print(qp.commutator(H, SX))
print(qp.commutator(H, SY))
print(qp.commutator(H, SZ))

##############################################################################
#
Expand All @@ -363,9 +363,9 @@ def IsingGenerators(n, bc="open"):
# This is easily verified by looking at the commutation relation between these operators that match :math:`[\hat{O}_i, \hat{O}_j] = 2i \varepsilon_{ij\ell} \hat{O}_\ell,` the defining
# property of :math:`\mathfrak{su}(2).`

print(qml.commutator(SX, SY) == (2j*SZ).simplify())
print(qml.commutator(SZ, SX) == (2j*SY).simplify())
print(qml.commutator(SY, SZ) == (2j*SX).simplify())
print(qp.commutator(SX, SY) == (2j*SZ).simplify())
print(qp.commutator(SZ, SX) == (2j*SY).simplify())
print(qp.commutator(SY, SZ) == (2j*SX).simplify())

##############################################################################
#
Expand Down
2 changes: 1 addition & 1 deletion demonstrations_v2/tutorial_liealgebra/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"executable_stable": true,
"executable_latest": true,
"dateOfPublication": "2024-02-27T00:00:00+00:00",
"dateOfLastModification": "2025-09-22T15:48:14+00:00",
"dateOfLastModification": "2026-04-17T15:48:14+00:00",
"categories": [
"Quantum Computing",
"Getting Started"
Expand Down
20 changes: 10 additions & 10 deletions demonstrations_v2/tutorial_liesim/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@

"""

import pennylane as qml
import pennylane as qp
from pennylane import X, Z, I
import numpy as np

Expand Down Expand Up @@ -186,7 +186,7 @@
# work with PauliSentence instances for efficiency
generators = [op.pauli_rep for op in generators]

dla = qml.lie_closure(generators, pauli=True)
dla = qp.lie_closure(generators, pauli=True)
dim_g = len(dla)

##############################################################################
Expand All @@ -207,7 +207,7 @@
# initial state |0x0| = (I + Z)/2, note that trace function
# below already normalizes by the dimension,
# so we can ommit the explicit factor /2
rho_in = qml.prod(*(I(i) + Z(i) for i in h_i.wires))
rho_in = qp.prod(*(I(i) + Z(i) for i in h_i.wires))
rho_in = rho_in.pauli_rep

e_in[i] = (h_i @ rho_in).trace()
Expand Down Expand Up @@ -239,7 +239,7 @@
# the forward pass of the expectation value computation. For demonstration purposes,
# we choose a random subset of ``depth=10`` generators for gates from the DLA.

adjoint_repr = qml.structure_constants(dla)
adjoint_repr = qp.structure_constants(dla)

depth = 10
gate_choice = np.random.choice(dim_g, size=depth)
Expand All @@ -264,13 +264,13 @@ def forward(theta):
##############################################################################
# As a sanity check, we compare the computation with the full state vector equivalent circuit.

H = 0.5 * qml.sum(*[op.operation() for op in generators])
H = 0.5 * qp.sum(*[op.operation() for op in generators])

@qml.qnode(qml.device("default.qubit"), interface="jax")
@qp.qnode(qp.device("default.qubit"), interface="jax")
def qnode(theta):
for i, mu in enumerate(gate_choice):
qml.exp(-1j * theta[i] * dla[mu].operation())
return qml.expval(H)
qp.exp(-1j * theta[i] * dla[mu].operation())
return qp.expval(H)

statevec_forward, statevec_backward = qnode(theta), jax.grad(qnode)(theta)
statevec_forward, statevec_backward
Expand All @@ -282,8 +282,8 @@ def qnode(theta):
# expectation value vector.

print(
qml.math.allclose(statevec_forward, gsim_forward),
qml.math.allclose(statevec_backward, gsim_backward),
qp.math.allclose(statevec_forward, gsim_forward),
qp.math.allclose(statevec_backward, gsim_backward),
)

##############################################################################
Expand Down
2 changes: 1 addition & 1 deletion demonstrations_v2/tutorial_liesim/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"executable_stable": true,
"executable_latest": true,
"dateOfPublication": "2024-06-07T00:00:00+00:00",
"dateOfLastModification": "2025-09-22T15:48:14+00:00",
"dateOfLastModification": "2026-04-17T15:48:14+00:00",
"categories": [
"Quantum Computing",
"Getting Started"
Expand Down
32 changes: 16 additions & 16 deletions demonstrations_v2/tutorial_liesim_extension/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@

"""

import pennylane as qml
import pennylane as qp
import numpy as np

from pennylane import X, Y, Z, I
Expand All @@ -99,7 +99,7 @@ def TFIM(n):
generators += [Z(i) for i in range(n)]
generators = [op.pauli_rep for op in generators]

dla = qml.lie_closure(generators, pauli=True)
dla = qp.lie_closure(generators, pauli=True)
dim_g = len(dla)
return generators, dla, dim_g

Expand All @@ -109,7 +109,7 @@ def TFIM(n):
# In regular :math:`\mathfrak{g}`-sim, the unitary evolution :math:`\mathcal{U}` of the expectation vector
# is simply generated by the adjoint representation :math:`U.`

adjoint_repr = qml.structure_constants(dla)
adjoint_repr = qp.structure_constants(dla)
gate = adjoint_repr[-1]
theta = 0.5

Expand All @@ -135,7 +135,7 @@ def TFIM(n):

p = dla[-5] @ dla[-1]
p = next(iter(p)) # strip any scalar coefficients
dla_vspace = qml.pauli.PauliVSpace(dla, dtype=complex)
dla_vspace = qp.pauli.PauliVSpace(dla, dtype=complex)
dla_vspace.is_independent(p.pauli_rep)


Expand Down Expand Up @@ -248,16 +248,16 @@ def exppw(theta, ps):
E_in = [E0_in, E1_in]

for i, hi in enumerate(dla):
rho_in = qml.prod(*(I(i) + Z(i) for i in hi.wires))
rho_in = qp.prod(*(I(i) + Z(i) for i in hi.wires))
rho_in = rho_in.pauli_rep

E_in[0][i] = (hi @ rho_in).trace()

for i, hi in enumerate(dla):
for j, hj in enumerate(dla):
prod = hi @ hj
if prod.wires != qml.wires.Wires([]):
rho_in = qml.prod(*(I(i) + Z(i) for i in prod.wires))
if prod.wires != qp.wires.Wires([]):
rho_in = qp.prod(*(I(i) + Z(i) for i in prod.wires))
else:
rho_in = PauliWord({}) # identity
rho_in = rho_in.pauli_rep
Expand Down Expand Up @@ -301,12 +301,12 @@ def exppw(theta, ps):
##############################################################################
# As a sanity check, let us compare this to the same circuit but using our default state vector simulator in PennyLane.

@qml.qnode(qml.device("default.qubit"))
@qp.qnode(qp.device("default.qubit"))
def true():
qml.exp(-1j * theta * dla[-1].operation())
qml.exp(-1j * 0.5 * p.operation())
qml.exp(-1j * 0.5 * dla[-2].operation())
return [qml.expval(op.operation()) for op in dla]
qp.exp(-1j * theta * dla[-1].operation())
qp.exp(-1j * 0.5 * p.operation())
qp.exp(-1j * 0.5 * dla[-2].operation())
return [qp.expval(op.operation()) for op in dla]

true_res = np.array(true())

Expand Down Expand Up @@ -362,7 +362,7 @@ def true():
# We now set up the moment vector spaces starting from the DLA and keep adding linearly independent product operators.

def Moment_step(ops, dla):
MomentX = qml.pauli.PauliVSpace(ops.copy())
MomentX = qp.pauli.PauliVSpace(ops.copy())
for i, op1 in enumerate(dla):
for op2 in ops[i+1:]:
prod = op1 @ op2
Expand Down Expand Up @@ -399,7 +399,7 @@ def Moment_step(ops, dla):
e_in = np.zeros((dim[comp_moment]), dtype=float)

for i, hi in enumerate(Moment[comp_moment]):
rho_in = qml.prod(*(I(i) + Z(i) for i in hi.wires))
rho_in = qp.prod(*(I(i) + Z(i) for i in hi.wires))
rho_in = rho_in.pauli_rep

e_in[i] = (hi @ rho_in).trace()
Expand All @@ -408,7 +408,7 @@ def Moment_step(ops, dla):
#
# Next, we compute the (pseudo-)adjoint representation of :math:`\mathcal{M}^1.`

adjoint_repr = qml.structure_constants(Moment[comp_moment])
adjoint_repr = qp.structure_constants(Moment[comp_moment])

##############################################################################
#
Expand Down Expand Up @@ -454,7 +454,7 @@ def Moment_step(ops, dla):
Moment.append(Moment_step(Moment[-1], dla))
dim.append(len(Moment[-1]))

tempdla = qml.lie_closure(dla + [Moment[1][-1]], pauli=True)
tempdla = qp.lie_closure(dla + [Moment[1][-1]], pauli=True)

dims_dla.append(dim_g)
dims_moment.append(dim)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"executable_stable": true,
"executable_latest": true,
"dateOfPublication": "2024-06-18T00:00:00+00:00",
"dateOfLastModification": "2025-09-22T15:48:14+00:00",
"dateOfLastModification": "2026-04-17T15:48:14+00:00",
"categories": [
"Quantum Computing",
"Quantum Machine Learning"
Expand Down
Loading
Loading