Skip to content

Commit

Permalink
Adding string representation for some operators (#6493)
Browse files Browse the repository at this point in the history
**Context:** The string representation format of some operators is
slightly different from others. This is because some do not have their
own string representation. Furthermore, the output of the Hadamard
operator should be updated since its string representation recently
changed.

**Description of the Change:**

- Change the output in the doc of the `qml.Hadamard` operator, since its
string representation changed during this release
- Add a string representation for the `qml.S` operator and change the
output in the doc
- Add a string representation for the `qml.T` operator and change the
output in the doc
- Add a string representation for the `qml.SX` operator and change the
output in the doc

**Benefits:** Correct doc output and more consistency among string
representation for non-parametrized single wire operators.

**Possible Drawbacks:** None that I can think of. This may cause
failures in some plugin tests that check explicitly the string
representation of such operators, but this failure should be immediate
to fix.

**Related GitHub Issues:** None.
  • Loading branch information
PietropaoloFrisoni authored Oct 31, 2024
1 parent d5d3c2b commit cd9fac9
Show file tree
Hide file tree
Showing 27 changed files with 130 additions and 100 deletions.
2 changes: 1 addition & 1 deletion doc/development/adding_operators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ The basic components of operators are the following:

>>> op = qml.PauliX(0)
>>> op.diagonalizing_gates()
[Hadamard(wires=[0])]
[H(0)]
>>> op.eigvals()
[ 1 -1]

Expand Down
2 changes: 1 addition & 1 deletion doc/introduction/inspecting_circuits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ Using the above example, we get:
<class 'networkx.classes.multidigraph.MultiDiGraph'>
>>> for k, v in g2.adjacency():
... print(k, v)
Hadamard(wires=[0]) {expval(Z(0)): {0: {'wire': 0}}}
H(0) {expval(Z(0)): {0: {'wire': 0}}}
CNOT(wires=[1, 2]) {CNOT(wires=[2, 3]): {0: {'wire': 2}}, CNOT(wires=[3, 1]): {0: {'wire': 1}}}
CNOT(wires=[2, 3]) {CNOT(wires=[3, 1]): {0: {'wire': 3}}}
CNOT(wires=[3, 1]) {}
Expand Down
2 changes: 1 addition & 1 deletion doc/introduction/operations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ These operator functions act on operators to produce new operators.
>>> op = qml.sum(qml.Hadamard(0), op)
>>> op = qml.s_prod(1.2, op)
>>> op
1.2 * (Hadamard(wires=[0]) + X(0) @ Z(1))
1.2 * (H(0) + X(0) @ Z(1))

Operator to Other functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
3 changes: 3 additions & 0 deletions doc/releases/changelog-0.39.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,9 @@

<h4>Other Improvements</h4>

* Added string representation for the `qml.S`, `qml.T`, and `qml.SX` operators.
[(#6493)](https://github.com/PennyLaneAI/pennylane/pull/6493)

* Added `qml.H` as an alias for the Hadamard operator.
[(#6450)](https://github.com/PennyLaneAI/pennylane/pull/6450)

Expand Down
2 changes: 1 addition & 1 deletion pennylane/ops/op_math/controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def circuit(x):
and individual :class:`~.operation.Operator`'s.
>>> qml.ctrl(qml.Hadamard(0), (1,2))
Controlled(Hadamard(wires=[0]), control_wires=[1, 2])
Controlled(H(0), control_wires=[1, 2])
Controlled operations work with all other forms of operator math and simplification:
Expand Down
38 changes: 19 additions & 19 deletions pennylane/ops/op_math/controlled_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ def compute_decomposition(wires): # pylint: disable=arguments-differ
**Example:**
>>> print(qml.CY.compute_decomposition([0, 1]))
[CRY(3.141592653589793, wires=[0, 1])), S(wires=[0])]
[CRY(3.141592653589793, wires=[0, 1])), S(0)]
"""
return [qml.CRY(np.pi, wires=wires), qml.S(wires=wires[0])]
Expand Down Expand Up @@ -709,20 +709,20 @@ def compute_decomposition(wires): # pylint: disable=arguments-differ
>>> qml.CCZ.compute_decomposition((0,1,2))
[CNOT(wires=[1, 2]),
Adjoint(T(wires=[2])),
Adjoint(T(2)),
CNOT(wires=[0, 2]),
T(wires=[2]),
T(2),
CNOT(wires=[1, 2]),
Adjoint(T(wires=[2])),
Adjoint(T(2)),
CNOT(wires=[0, 2]),
T(wires=[2]),
T(wires=[1]),
T(2),
T(1),
CNOT(wires=[0, 1]),
Hadamard(wires=[2]),
T(wires=[0]),
Adjoint(T(wires=[1])),
H(2),
T(0),
Adjoint(T(1)),
CNOT(wires=[0, 1]),
Hadamard(wires=[2])]
H(2)]
"""
return [
Expand Down Expand Up @@ -962,20 +962,20 @@ def compute_decomposition(wires): # pylint: disable=arguments-differ
**Example:**
>>> qml.Toffoli.compute_decomposition((0,1,2))
[Hadamard(wires=[2]),
[H(2),
CNOT(wires=[1, 2]),
Adjoint(T(wires=[2])),
Adjoint(T(2)),
CNOT(wires=[0, 2]),
T(wires=[2]),
T(2),
CNOT(wires=[1, 2]),
Adjoint(T(wires=[2])),
Adjoint(T(2)),
CNOT(wires=[0, 2]),
T(wires=[2]),
T(wires=[1]),
T(2),
T(1),
CNOT(wires=[0, 1]),
Hadamard(wires=[2]),
T(wires=[0]),
Adjoint(T(wires=[1])),
H(2),
T(0),
Adjoint(T(1)),
CNOT(wires=[0, 1])]
"""
Expand Down
4 changes: 2 additions & 2 deletions pennylane/ops/op_math/linear_combination.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class LinearCombination(Sum):
>>> obs = [qml.X(0) @ qml.Z(1), qml.Z(0) @ qml.Hadamard(2)]
>>> H = qml.ops.LinearCombination(coeffs, obs)
>>> print(H)
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ Hadamard(wires=[2]))
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ H(2))
The coefficients can be a trainable tensor, for example:
Expand All @@ -67,7 +67,7 @@ class LinearCombination(Sum):
>>> obs = [qml.X(0) @ qml.Z(1), qml.Z(0) @ qml.Hadamard(2)]
>>> H = qml.ops.LinearCombination(coeffs, obs)
>>> print(H)
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ Hadamard(wires=[2]))
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ H(2))
A ``LinearCombination`` can store information on which commuting observables should be measured together in
Expand Down
4 changes: 2 additions & 2 deletions pennylane/ops/op_math/pow.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def pow(base, z=1, lazy=True, id=None):
>>> qml.pow(qml.X(0), 0.5)
X(0)**0.5
>>> qml.pow(qml.X(0), 0.5, lazy=False)
SX(wires=[0])
SX(0)
>>> qml.pow(qml.X(0), 0.1, lazy=False)
X(0)**0.1
>>> qml.pow(qml.X(0), 2, lazy=False)
Expand Down Expand Up @@ -118,7 +118,7 @@ class Pow(ScalarSymbolicOp):
>>> sqrt_x = Pow(qml.X(0), 0.5)
>>> sqrt_x.decomposition()
[SX(wires=[0])]
[SX(0)]
>>> qml.matrix(sqrt_x)
array([[0.5+0.5j, 0.5-0.5j],
[0.5-0.5j, 0.5+0.5j]])
Expand Down
4 changes: 2 additions & 2 deletions pennylane/ops/qubit/hamiltonian.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ class Hamiltonian(Observable):
>>> obs = [qml.X(0) @ qml.Z(1), qml.Z(0) @ qml.Hadamard(2)]
>>> H = qml.Hamiltonian(coeffs, obs)
>>> print(H)
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ Hadamard(wires=[2]))
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ H(2))
The coefficients can be a trainable tensor, for example:
>>> coeffs = tf.Variable([0.2, -0.543], dtype=tf.double)
>>> obs = [qml.X(0) @ qml.Z(1), qml.Z(0) @ qml.Hadamard(2)]
>>> H = qml.Hamiltonian(coeffs, obs)
>>> print(H)
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ Hadamard(wires=[2]))
0.2 * (X(0) @ Z(1)) + -0.543 * (Z(0) @ H(2))
A ``qml.Hamiltonian`` stores information on which commuting observables should be measured
together in a circuit:
Expand Down
47 changes: 34 additions & 13 deletions pennylane/ops/qubit/non_parametric_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def compute_diagonalizing_gates(wires: WiresLike) -> list[qml.operation.Operator
**Example**
>>> print(qml.X.compute_diagonalizing_gates(wires=[0]))
[Hadamard(wires=[0])]
[H(0)]
"""
return [Hadamard(wires=wires)]

Expand Down Expand Up @@ -529,7 +529,7 @@ def compute_diagonalizing_gates(wires: WiresLike) -> list[qml.operation.Operator
**Example**
>>> print(qml.Y.compute_diagonalizing_gates(wires=[0]))
[Z(0), S(wires=[0]), Hadamard(wires=[0])]
[Z(0), S(0), H(0)]
"""
return [
Z(wires=wires),
Expand Down Expand Up @@ -815,6 +815,13 @@ class S(Operation):

batch_size = None

def __repr__(self) -> str:
"""String representation."""
wire = self.wires[0]
if isinstance(wire, str):
return f"S('{wire}')"
return f"S({wire})"

@staticmethod
@lru_cache()
def compute_matrix() -> np.ndarray: # pylint: disable=arguments-differ
Expand Down Expand Up @@ -927,6 +934,13 @@ class T(Operation):

batch_size = None

def __repr__(self) -> str:
"""String representation."""
wire = self.wires[0]
if isinstance(wire, str):
return f"T('{wire}')"
return f"T({wire})"

@staticmethod
@lru_cache()
def compute_matrix() -> np.ndarray: # pylint: disable=arguments-differ
Expand Down Expand Up @@ -1037,6 +1051,13 @@ class SX(Operation):

basis = "X"

def __repr__(self) -> str:
"""String representation."""
wire = self.wires[0]
if isinstance(wire, str):
return f"SX('{wire}')"
return f"SX({wire})"

@staticmethod
@lru_cache()
def compute_matrix() -> np.ndarray: # pylint: disable=arguments-differ
Expand Down Expand Up @@ -1322,7 +1343,7 @@ def compute_decomposition(wires: WiresLike) -> list[qml.operation.Operator]:
[Z(0),
CNOT(wires=[0, 1]),
SX(wires=[1]),
SX(1),
RX(1.5707963267948966, wires=[0]),
RY(1.5707963267948966, wires=[0]),
RX(1.5707963267948966, wires=[0])]
Expand Down Expand Up @@ -1438,12 +1459,12 @@ def compute_decomposition(wires: WiresLike) -> list[qml.operation.Operator]:
**Example:**
>>> print(qml.ISWAP.compute_decomposition((0,1)))
[S(wires=[0]),
S(wires=[1]),
Hadamard(wires=[0]),
[S(0),
S(1),
H(0),
CNOT(wires=[0, 1]),
CNOT(wires=[1, 0]),
Hadamard(wires=[1])]
H(1)]
"""
return [
Expand Down Expand Up @@ -1563,18 +1584,18 @@ def compute_decomposition(wires: WiresLike) -> list[qml.operation.Operator]:
**Example:**
>>> print(qml.SISWAP.compute_decomposition((0,1)))
[SX(wires=[0]),
[SX(0),
RZ(1.5707963267948966, wires=[0]),
CNOT(wires=[0, 1]),
SX(wires=[0]),
SX(0),
RZ(5.497787143782138, wires=[0]),
SX(wires=[0]),
SX(0),
RZ(1.5707963267948966, wires=[0]),
SX(wires=[1]),
SX(1),
RZ(5.497787143782138, wires=[1]),
CNOT(wires=[0, 1]),
SX(wires=[0]),
SX(wires=[1])]
SX(0),
SX(1)]
"""
return [
Expand Down
6 changes: 3 additions & 3 deletions pennylane/ops/qubit/parametric_ops_multi_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,10 +482,10 @@ def compute_decomposition(
**Example:**
>>> qml.PauliRot.compute_decomposition(1.2, "XY", wires=(0,1))
[Hadamard(wires=[0]),
[H(0),
RX(1.5707963267948966, wires=[1]),
MultiRZ(1.2, wires=[0, 1]),
Hadamard(wires=[0]),
H(0),
RX(-1.5707963267948966, wires=[1])]
"""
Expand Down Expand Up @@ -1286,7 +1286,7 @@ def compute_decomposition(phi: TensorLike, wires: WiresLike) -> list["qml.operat
**Example:**
>>> qml.IsingXY.compute_decomposition(1.23, wires=(0,1))
[Hadamard(wires=[0]), CY(wires=[0, 1]), RY(0.615, wires=[0]), RX(-0.615, wires=[1]), CY(wires=[0, 1]), Hadamard(wires=[0])]
[H(0), CY(wires=[0, 1]), RY(0.615, wires=[0]), RX(-0.615, wires=[1]), CY(wires=[0, 1]), H(0)]
"""
return [
Expand Down
2 changes: 1 addition & 1 deletion pennylane/ops/qubit/parametric_ops_single_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,7 @@ def simplify(self) -> "Rot":
>>> qml.Rot(np.pi / 2, 0.1, -np.pi / 2, wires=0).simplify()
RX(0.1, wires=[0])
>>> qml.Rot(np.pi, np.pi/2, 0, 0).simplify()
Hadamard(wires=[0])
H(0)
"""
p0, p1, p2 = [p % (4 * np.pi) for p in self.data]
Expand Down
44 changes: 22 additions & 22 deletions pennylane/ops/qubit/qchem_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,22 +224,22 @@ def compute_decomposition(phi: TensorLike, wires: WiresLike) -> list["qml.operat
**Example:**
>>> qml.SingleExcitation.compute_decomposition(1.23, wires=(0,1))
[Adjoint(T(wires=[0])),
Hadamard(wires=[0]),
S(wires=[0]),
Adjoint(T(wires=[1])),
Adjoint(S(wires=[1])),
Hadamard(wires=[1]),
[Adjoint(T(0)),
H(0),
S(0),
Adjoint(T(1)),
Adjoint(S(1)),
H(1),
CNOT(wires=[1, 0]),
RZ(-0.615, wires=[0]),
RY(0.615, wires=[1]),
CNOT(wires=[1, 0]),
Adjoint(S(wires=[0])),
Hadamard(wires=[0]),
T(wires=[0]),
Hadamard(wires=[1]),
S(wires=[1]),
T(wires=[1])]
Adjoint(S(0)),
H(0),
T(0),
H(1),
S(1),
T(1)]
"""
# This decomposition was found by plugging the matrix representation
Expand Down Expand Up @@ -680,14 +680,14 @@ def compute_decomposition(phi: TensorLike, wires: WiresLike) -> list["qml.operat
>>> qml.DoubleExcitation.compute_decomposition(1.23, wires=(0,1,2,3))
[CNOT(wires=[2, 3]),
CNOT(wires=[0, 2]),
Hadamard(wires=[3]),
Hadamard(wires=[0]),
H(3),
H(0),
CNOT(wires=[2, 3]),
CNOT(wires=[0, 1]),
RY(0.15375, wires=[1]),
RY(-0.15375, wires=[0]),
CNOT(wires=[0, 3]),
Hadamard(wires=[3]),
H(3),
CNOT(wires=[3, 1]),
RY(0.15375, wires=[1]),
RY(-0.15375, wires=[0]),
Expand All @@ -696,14 +696,14 @@ def compute_decomposition(phi: TensorLike, wires: WiresLike) -> list["qml.operat
RY(-0.15375, wires=[1]),
RY(0.15375, wires=[0]),
CNOT(wires=[3, 1]),
Hadamard(wires=[3]),
H(3),
CNOT(wires=[0, 3]),
RY(-0.15375, wires=[1]),
RY(0.15375, wires=[0]),
CNOT(wires=[0, 1]),
CNOT(wires=[2, 0]),
Hadamard(wires=[0]),
Hadamard(wires=[3]),
H(0),
H(3),
CNOT(wires=[0, 2]),
CNOT(wires=[2, 3])]
Expand Down Expand Up @@ -1268,11 +1268,11 @@ def compute_decomposition(phi: TensorLike, wires: WiresLike) -> list["qml.operat
**Example:**
>>> qml.FermionicSWAP.compute_decomposition(0.2, wires=(0, 1))
[Hadamard(wires=[0]),
Hadamard(wires=[1]),
[H(0),
H(1),
MultiRZ(0.1, wires=[0, 1]),
Hadamard(wires=[0]),
Hadamard(wires=[1]),
H(0),
H(1),
RX(1.5707963267948966, wires=[0]),
RX(1.5707963267948966, wires=[1]),
MultiRZ(0.1, wires=[0, 1]),
Expand Down
Loading

0 comments on commit cd9fac9

Please sign in to comment.