Skip to content

Commit

Permalink
Merge branch 'master' into sprod-terms
Browse files Browse the repository at this point in the history
  • Loading branch information
astralcai committed Jul 12, 2024
2 parents eb86f21 + dbb26f2 commit 732d867
Show file tree
Hide file tree
Showing 25 changed files with 103 additions and 54 deletions.
4 changes: 2 additions & 2 deletions doc/development/adding_operators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ The basic components of operators are the following:
#. **The subsystems that the operator addresses** (:attr:`.Operator.wires`), which mathematically speaking defines the subspace that it acts on.

>>> op.wires
<Wires = ['a']>
Wires(['a'])

#. **Trainable parameters** (:attr:`.Operator.parameters`) that the map depends on, such as a rotation angle,
which can be fed to the operator as tensor-like objects. For example, since we used jax arrays to
Expand Down Expand Up @@ -237,7 +237,7 @@ If the above operator omitted the ``_unflatten`` custom definition, it would rai
The above exception was the direct cause of the following exception:
AssertionError: FlipAndRotate._unflatten must be able to reproduce the original operation
from (0.1,) and (<Wires = ['q3', 'q1']>, (('do_flip', True),)). You may need to override
from (0.1,) and (Wires(['q3', 'q1']), (('do_flip', True),)). You may need to override
either the _unflatten or _flatten method.
For local testing, try type(op)._unflatten(*op._flatten())
Expand Down
2 changes: 1 addition & 1 deletion doc/development/guide/architecture.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Rot
>>> op.hyperparameters
{}
>>> op.wires
<Wires = ['a']>
Wires(['a'])

Operators can optionally define the transformation they implement via
symbolic or numerical representations. Here are two examples, and you find more
Expand Down
10 changes: 5 additions & 5 deletions doc/development/plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ For example:
from pennylane.wires import Wires
wires = Wires(['auxiliary', 0, 1])
print(wires[0]) # <Wires = ['auxiliary']>
print(wires[0]) # Wires(['auxiliary'])
print(wires.labels) # ('auxiliary', 0, 1)
As shown in the section on :doc:`/introduction/circuits`, a device can be created with custom wire labels:
Expand All @@ -351,10 +351,10 @@ object and store it in their ``wires`` attribute.

.. code-block:: python
print(dev.wires) # <Wires = ['q11', 'q12', 'q21', 'q22']>
print(dev.wires) # Wires(['q11', 'q12', 'q21', 'q22'])
op = Gate2(wires=['q21','q11'])
print(op.wires) # <Wires = ['q21', 'q11']>
print(op.wires) # Wires(['q21', 'q11'])
When the device applies operations, it needs to translate
``op.wires`` into wire labels that the backend "understands". This can be done with the
Expand All @@ -365,7 +365,7 @@ but changes the labels according to the ``wire_map`` attribute of the device whi
# inside the class defining 'my.device', which inherits from the base Device class
device_wires = self.map_wires(op.wires)
print(device_wires) # <Wires = [2, 0]>
print(device_wires) # Wires([2, 0])
By default, the map translates the custom labels ``'q11'``, ``'q12'``, ``'q21'``, ``'q22'`` to
consecutive integers ``0``, ``1``, ``2``, ``3``. If a device uses a different wire labeling,
Expand Down Expand Up @@ -527,4 +527,4 @@ Users can then import this operator directly from your plugin, and use it when d

If the custom operator is diagonal in the computational basis, it can be added to the
``diagonal_in_z_basis`` attribute in ``pennylane.ops.qubit.attributes``. Devices can use this
information to implement faster simulations.
information to implement faster simulations.
9 changes: 9 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
* `QuantumScript.hash` is now cached, leading to performance improvements.
[(#5919)](https://github.com/PennyLaneAI/pennylane/pull/5919)

* The representation for `Wires` has now changed to be more copy-paste friendly.
[(#5958)](https://github.com/PennyLaneAI/pennylane/pull/5958)

* Observable validation for `default.qubit` is now based on execution mode (analytic vs. finite shots) and measurement type (sample measurement vs. state measurement).
[(#5890)](https://github.com/PennyLaneAI/pennylane/pull/5890)

Expand All @@ -48,6 +51,10 @@

<h3>Bug fixes 🐛</h3>

* `qml.devices.qubit.measure_with_samples` now returns the correct result if the provided measurements
contain sum of operators acting on the same wire.
[(#5978)](https://github.com/PennyLaneAI/pennylane/pull/5978)

* `qml.AmplitudeEmbedding` has better support for features using low precision integer data types.
[(#5969)](https://github.com/PennyLaneAI/pennylane/pull/5969)

Expand All @@ -58,7 +65,9 @@ This release contains contributions from (in alphabetical order):
Ahmed Darwish,
Astral Cai,
Yushao Chen,
Pietropaolo Frisoni,
Christina Lee,
Austin Huang,
William Maxwell,
Vincent Michaud-Rioux,
Mudit Pandey,
Expand Down
2 changes: 1 addition & 1 deletion pennylane/_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ def define_wire_map(self, wires):
>>> dev = device('my.device', wires=['b', 'a'])
>>> dev.wire_map()
OrderedDict( [(<Wires = ['a']>, <Wires = [0]>), (<Wires = ['b']>, <Wires = [1]>)])
OrderedDict( [(Wires(['a']), Wires([0])), (Wires(['b']), Wires([1]))])
"""
consecutive_wires = Wires(range(self.num_wires))

Expand Down
2 changes: 1 addition & 1 deletion pennylane/_qubit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ def apply(self, operations, **kwargs):
>>> op.name # returns the operation name
"RX"
>>> op.wires # returns a Wires object representing the wires that the operation acts on
<Wires = [0]>
Wires([0])
>>> op.parameters # returns a list of parameters
[0.2]
Expand Down
4 changes: 3 additions & 1 deletion pennylane/devices/qubit/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
ShadowExpvalMP,
Shots,
)
from pennylane.ops import Hamiltonian, LinearCombination, Sum
from pennylane.ops import Hamiltonian, LinearCombination, Prod, SProd, Sum
from pennylane.typing import TensorLike

from .apply_operation import apply_operation
Expand Down Expand Up @@ -65,6 +65,8 @@ def _group_measurements(mps: List[Union[SampleMeasurement, ClassicalShadowMP, Sh
mp_no_obs_indices = []

for i, mp in enumerate(mps):
if isinstance(mp.obs, (Sum, SProd, Prod)):
mps[i].obs = qml.simplify(mp.obs)
if isinstance(mp, (ClassicalShadowMP, ShadowExpvalMP)):
mp_other_obs.append([mp])
mp_other_obs_indices.append([i])
Expand Down
10 changes: 5 additions & 5 deletions pennylane/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ def circuit(angle):
>>> op = qml.PauliRot(1.2, "XY", wires=(0,1))
>>> op._flatten()
((1.2,), (<Wires = [0, 1]>, (('pauli_word', 'XY'),)))
((1.2,), (Wires([0, 1]), (('pauli_word', 'XY'),)))
>>> qml.PauliRot._unflatten(*op._flatten())
PauliRot(1.2, XY, wires=[0, 1])
Expand Down Expand Up @@ -1629,7 +1629,7 @@ def _flatten(self):
>>> op = qml.ctrl(qml.U2(3.4, 4.5, wires="a"), ("b", "c") )
>>> op._flatten()
((U2(3.4, 4.5, wires=['a']),),
(<Wires = ['b', 'c']>, (True, True), <Wires = []>))
(Wires(['b', 'c']), (True, True), Wires([])))
"""
hashable_hyperparameters = tuple(
Expand All @@ -1652,11 +1652,11 @@ def _unflatten(cls, data, metadata):
>>> op = qml.Rot(1.2, 2.3, 3.4, wires=0)
>>> op._flatten()
((1.2, 2.3, 3.4), (<Wires = [0]>, ()))
((1.2, 2.3, 3.4), (Wires([0]), ()))
>>> qml.Rot._unflatten(*op._flatten())
>>> op = qml.PauliRot(1.2, "XY", wires=(0,1))
>>> op._flatten()
((1.2,), (<Wires = [0, 1]>, (('pauli_word', 'XY'),)))
((1.2,), (Wires([0, 1]), (('pauli_word', 'XY'),)))
>>> op = qml.ctrl(qml.U2(3.4, 4.5, wires="a"), ("b", "c") )
>>> type(op)._unflatten(*op._flatten())
Controlled(U2(3.4, 4.5, wires=['a']), control_wires=['b', 'c'])
Expand Down Expand Up @@ -1968,7 +1968,7 @@ def _obs_data(self):
>>> tensor = qml.X(0) @ qml.Z(1)
>>> print(tensor._obs_data())
{("PauliZ", <Wires = [1]>, ()), ("PauliX", <Wires = [0]>, ())}
{("PauliZ", Wires([1]), ()), ("PauliX", Wires([0]), ())}
"""
obs = Tensor(self).non_identity_obs
tensor = set()
Expand Down
6 changes: 3 additions & 3 deletions pennylane/ops/op_math/controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,11 +322,11 @@ class Controlled(SymbolicOp):
>>> op.data
(1.234,)
>>> op.wires
<Wires = [0, 1]>
Wires([0, 1])
>>> op.control_wires
<Wires = [0]>
Wires([0])
>>> op.target_wires
<Wires = [1]>
Wires([1])
Control values are lists of booleans, indicating whether or not to control on the
``0==False`` value or the ``1==True`` wire.
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 @@ -662,8 +662,8 @@ def _obs_data(self):
>>> H = qml.Hamiltonian([1, 1], [qml.X(0) @ qml.X(1), qml.Z(0)])
>>> print(H._obs_data())
{(1, frozenset({('PauliX', <Wires = [1]>, ()), ('PauliX', <Wires = [0]>, ())})),
(1, frozenset({('PauliZ', <Wires = [0]>, ())}))}
{(1, frozenset({('PauliX', Wires([1]), ()), ('PauliX', Wires([0]), ())})),
(1, frozenset({('PauliZ', Wires([0]), ())}))}
"""
data = set()

Expand Down
4 changes: 2 additions & 2 deletions pennylane/pytrees/pytrees.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class PyTreeStructure:
>>> op = qml.adjoint(qml.RX(0.1, 0))
>>> data, structure = qml.pytrees.flatten(op)
>>> structure
PyTree(AdjointOperation, (), [PyTree(RX, (<Wires = [0]>, ()), [Leaf])])
PyTree(AdjointOperation, (), [PyTree(RX, (Wires([0]), ()), [Leaf])])
A leaf is defined as just a ``PyTreeStructure`` with ``type_=None``.
"""
Expand Down Expand Up @@ -236,7 +236,7 @@ def flatten(obj: Any) -> tuple[list[Any], PyTreeStructure]:
[1.2, 2.3, 3.4]
>>> structure
<PyTree(AdjointOperation, (), (<PyTree(Rot, (<Wires = [0]>, ()), (Leaf, Leaf, Leaf))>,))>
<PyTree(AdjointOperation, (), (<PyTree(Rot, (Wires([0]), ()), (Leaf, Leaf, Leaf))>,))>
"""
flatten_fn = flatten_registrations.get(type(obj), None)
if flatten_fn is None:
Expand Down
10 changes: 5 additions & 5 deletions pennylane/qchem/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,23 @@ def _process_wires(wires, n_wires=None):
>>> # consec int wires if no wires mapping provided, ie. identity map: 0<->0, 1<->1, 2<->2
>>> _process_wires(None, 3)
<Wires = [0, 1, 2]>
Wires([0, 1, 2])
>>> # List as mapping, qubit indices with wire label values: 0<->w0, 1<->w1, 2<->w2
>>> _process_wires(['w0','w1','w2'])
<Wires = ['w0', 'w1', 'w2']>
Wires(['w0', 'w1', 'w2'])
>>> # Wires as mapping, qubit indices with wire label values: 0<->w0, 1<->w1, 2<->w2
>>> _process_wires(Wires(['w0', 'w1', 'w2']))
<Wires = ['w0', 'w1', 'w2']>
Wires(['w0', 'w1', 'w2'])
>>> # Dict as partial mapping, int qubits keys to wire label values: 0->w0, 1 unchanged, 2->w2
>>> _process_wires({0:'w0',2:'w2'})
<Wires = ['w0', 1, 'w2']>
Wires(['w0', 1, 'w2'])
>>> # Dict as mapping, wires label keys to consec int qubit values: w2->2, w0->0, w1->1
>>> _process_wires({'w2':2, 'w0':0, 'w1':1})
<Wires = ['w0', 'w1', 'w2']>
Wires(['w0', 'w1', 'w2'])
"""

# infer from wires, or assume 1 if wires is not of accepted types.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/qchem/openfermion_pyscf.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ def dipole_of(
>>> coordinates = np.array([0.028, 0.054, 0.0, 0.986, 1.610, 0.0, 1.855, 0.002, 0.0])
>>> dipole_obs = dipole_of(symbols, coordinates, charge=1)
>>> print([(h.wires) for h in dipole_obs])
[<Wires = [0, 1, 2, 3, 4, 5]>, <Wires = [0, 1, 2, 3, 4, 5]>, <Wires = [0]>]
[Wires([0, 1, 2, 3, 4, 5]), Wires([0, 1, 2, 3, 4, 5]), Wires([0])]
>>> dipole_obs[0] # x-component of D
(
Expand Down
2 changes: 1 addition & 1 deletion pennylane/tape/tape.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ class QuantumTape(QuantumScript, AnnotatedQueue):
>>> tape.get_parameters()
[0.432, 0.543, 0.133]
>>> tape.wires
<Wires = [0, 'a']>
Wires([0, 'a'])
>>> tape.num_params
3
Expand Down
2 changes: 1 addition & 1 deletion pennylane/templates/subroutines/qubitization.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def compute_decomposition(*_, **kwargs): # pylint: disable=arguments-differ
**Example:**
>>> print(qml.Qubitization.compute_decomposition(hamiltonian = 0.1 * qml.Z(0), control = 1))
[AmplitudeEmbedding(array([1., 0.]), wires=[1]), Select(ops=(Z(0),), control=<Wires = [1]>), Adjoint(AmplitudeEmbedding(array([1., 0.]), wires=[1])), Reflection(, wires=[0])]
[AmplitudeEmbedding(array([1., 0.]), wires=[1]), Select(ops=(Z(0),), control=Wires([1])), Adjoint(AmplitudeEmbedding(array([1., 0.]), wires=[1])), Reflection(, wires=[0])]
"""

Expand Down
6 changes: 3 additions & 3 deletions pennylane/templates/subroutines/trotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ def _flatten(self):
>>> op = qml.ctrl(qml.U2(3.4, 4.5, wires="a"), ("b", "c") )
>>> op._flatten()
((U2(3.4, 4.5, wires=['a']),),
(<Wires = ['b', 'c']>, (True, True), <Wires = []>))
(Wires(['b', 'c']), (True, True), Wires([])))
"""
hamiltonian = self.hyperparameters["base"]
time = self.data[-1]
Expand All @@ -399,11 +399,11 @@ def _unflatten(cls, data, metadata):
>>> op = qml.Rot(1.2, 2.3, 3.4, wires=0)
>>> op._flatten()
((1.2, 2.3, 3.4), (<Wires = [0]>, ()))
((1.2, 2.3, 3.4), (Wires([0]), ()))
>>> qml.Rot._unflatten(*op._flatten())
>>> op = qml.PauliRot(1.2, "XY", wires=(0,1))
>>> op._flatten()
((1.2,), (<Wires = [0, 1]>, (('pauli_word', 'XY'),)))
((1.2,), (Wires([0, 1]), (('pauli_word', 'XY'),)))
>>> op = qml.ctrl(qml.U2(3.4, 4.5, wires="a"), ("b", "c") )
>>> type(op)._unflatten(*op._flatten())
Controlled(U2(3.4, 4.5, wires=['a']), control_wires=['b', 'c'])
Expand Down
18 changes: 9 additions & 9 deletions pennylane/wires.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def __contains__(self, item):

def __repr__(self):
"""Method defining the string representation of this class."""
return f"<Wires = {list(self._labels)}>"
return f"Wires({list(self._labels)})"

def __eq__(self, other):
"""Method to support the '==' operator.
Expand Down Expand Up @@ -286,7 +286,7 @@ def map(self, wire_map):
>>> wires = Wires(['a', 'b', 'c'])
>>> wire_map = {'a': 4, 'b':2, 'c': 3}
>>> wires.map(wire_map)
<Wires = [4, 2, 3]>
Wires([4, 2, 3])
"""
# Make sure wire_map has `Wires` keys and values so that the `in` operator always works

Expand Down Expand Up @@ -322,17 +322,17 @@ def subset(self, indices, periodic_boundary=False):
>>> wires = Wires([4, 0, 1, 5, 6])
>>> wires.subset([2, 3, 0])
<Wires = [1, 5, 4]>
Wires([1, 5, 4])
>>> wires.subset(1)
<Wires = [0]>
Wires([0])
If ``periodic_boundary`` is True, the modulo of the number of wires of an index is used instead of an index,
so that ``wires.subset(i) == wires.subset(i % n_wires)`` where ``n_wires`` is the number of wires of this
object.
>>> wires = Wires([4, 0, 1, 5, 6])
>>> wires.subset([5, 1, 7], periodic_boundary=True)
<Wires = [4, 0, 1]>
Wires([4, 0, 1])
"""

Expand Down Expand Up @@ -389,9 +389,9 @@ def shared_wires(list_of_wires):
>>> wires2 = Wires([3, 0, 4])
>>> wires3 = Wires([4, 0])
>>> Wires.shared_wires([wires1, wires2, wires3])
<Wires = [4, 0]>
Wires([4, 0])
>>> Wires.shared_wires([wires2, wires1, wires3])
<Wires = [0, 4]>
Wires([0, 4])
"""

for wires in list_of_wires:
Expand Down Expand Up @@ -431,7 +431,7 @@ def all_wires(list_of_wires, sort=False):
>>> wires3 = Wires([5, 3])
>>> list_of_wires = [wires1, wires2, wires3]
>>> Wires.all_wires(list_of_wires)
<Wires = [4, 0, 1, 3, 5]>
Wires([4, 0, 1, 3, 5])
"""
converted_wires = (
wires if isinstance(wires, Wires) else Wires(wires) for wires in list_of_wires
Expand Down Expand Up @@ -463,7 +463,7 @@ def unique_wires(list_of_wires):
>>> wires2 = Wires([0, 2, 3])
>>> wires3 = Wires([5, 3])
>>> Wires.unique_wires([wires1, wires2, wires3])
<Wires = [4, 1, 2, 5]>
Wires([4, 1, 2, 5])
"""

for wires in list_of_wires:
Expand Down
4 changes: 2 additions & 2 deletions pennylane/workflow/return_types_spec.rst
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ or ``qml.state()``. In such a case, the measurement process instance should have
The shape of the result object may be dictated either by the device or the other operations present in the circuit.

>>> qml.probs().wires
<Wires = []>
Wires([])
>>> tape = qml.tape.QuantumScript([qml.S(0)], (qml.probs(),))
>>> qml.device('default.qubit').execute(tape)
array([1., 0.])
Expand Down Expand Up @@ -176,4 +176,4 @@ where each entry corresponds to the result for the corresponding tape.
>>> tape3 = qml.tape.QuantumScript([], [qml.expval(qml.Z(0)), qml.expval(qml.X(0))])
>>> batch = (tape1, tape2, tape3)
>>> qml.device('default.qubit').execute(batch)
(array([0.+0.j, 1.+0.j]), {'0': 50, '1': 50}, (1.0, 0.0))
(array([0.+0.j, 1.+0.j]), {'0': 50, '1': 50}, (1.0, 0.0))
Loading

0 comments on commit 732d867

Please sign in to comment.