Skip to content

Commit

Permalink
Merge branch 'master' into prob-interface-in-probs-process-density-ma…
Browse files Browse the repository at this point in the history
…trix
  • Loading branch information
JerryChen97 authored Dec 20, 2024
2 parents 39559bd + 045a67d commit 922f808
Show file tree
Hide file tree
Showing 15 changed files with 141 additions and 79 deletions.
4 changes: 4 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ such as `shots`, `rng` and `prng_key`.

<h4>Other Improvements</h4>

* `Wires` object usage across Pennylane source code has been tidied up.
[(#6689)](https://github.com/PennyLaneAI/pennylane/pull/6689)

* `qml.equal` now supports `PauliWord` and `PauliSentence` instances.
[(#6703)](https://github.com/PennyLaneAI/pennylane/pull/6703)

Expand Down Expand Up @@ -375,6 +378,7 @@ such as `shots`, `rng` and `prng_key`.

* PennyLane is compatible with `quimb 1.10.0`.
[(#6630)](https://github.com/PennyLaneAI/pennylane/pull/6630)
[(#6736)](https://github.com/PennyLaneAI/pennylane/pull/6736)

* Add developer focused `run` function to `qml.workflow` module.
[(#6657)](https://github.com/PennyLaneAI/pennylane/pull/6657)
Expand Down
32 changes: 21 additions & 11 deletions pennylane/devices/default_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,8 @@ class DefaultTensor(Device):
`quimb's tensor_contract documentation <https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_core/index.html#quimb.tensor.tensor_core.tensor_contract>`_.
Default is ``"auto-hq"``.
local_simplify (str): The simplification sequence to apply to the tensor network for computing local expectation values.
For a complete list of available simplification options, see the
`quimb's full_simplify documentation <https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_core/index.html#quimb.tensor.tensor_core.TensorNetwork.full_simplify>`_.
At present, this argument can only be provided when the TN method is used. For a complete list of available simplification options,
see the `quimb's full_simplify documentation <https://quimb.readthedocs.io/en/latest/autoapi/quimb/tensor/tensor_core/index.html#quimb.tensor.tensor_core.TensorNetwork.full_simplify>`_.
Default is ``"ADCRS"``.
Expand Down Expand Up @@ -400,8 +400,10 @@ def __init__(
self._max_bond_dim = kwargs.get("max_bond_dim", None)
self._cutoff = kwargs.get("cutoff", None)

# options both for MPS and TN
# options for TN
self._local_simplify = kwargs.get("local_simplify", "ADCRS")

# options both for MPS and TN
self._contraction_optimizer = kwargs.get("contraction_optimizer", "auto-hq")
self._contract = None

Expand Down Expand Up @@ -810,14 +812,22 @@ def _local_expectation(self, matrix, wires) -> float:
# after the execution, we could avoid copying the circuit.
qc = self._quimb_circuit.copy()

exp_val = qc.local_expectation(
matrix,
wires,
dtype=self._c_dtype.__name__,
optimize=self._contraction_optimizer,
simplify_sequence=self._local_simplify,
simplify_atol=0.0,
)
if self.method == "mps":
exp_val = qc.local_expectation(
matrix,
wires,
dtype=self._c_dtype.__name__,
optimize=self._contraction_optimizer,
)
else:
exp_val = qc.local_expectation(
matrix,
wires,
dtype=self._c_dtype.__name__,
optimize=self._contraction_optimizer,
simplify_sequence=self._local_simplify,
simplify_atol=0.0,
)

return float(np.real(exp_val))

Expand Down
9 changes: 6 additions & 3 deletions pennylane/measurements/classical_shadow.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

import pennylane as qml
from pennylane.operation import Operator
from pennylane.wires import Wires
from pennylane.wires import Wires, WiresLike

from .measurements import MeasurementShapeError, MeasurementTransform, Shadow, ShadowExpval

Expand Down Expand Up @@ -89,7 +89,7 @@ def circuit(x, obs):
return ShadowExpvalMP(H=H, seed=seed, k=k)


def classical_shadow(wires, seed=None):
def classical_shadow(wires: WiresLike, seed=None):
"""
The classical shadow measurement protocol.
Expand Down Expand Up @@ -227,7 +227,10 @@ class ClassicalShadowMP(MeasurementTransform):
"""

def __init__(
self, wires: Optional[Wires] = None, seed: Optional[int] = None, id: Optional[str] = None
self,
wires: Optional[WiresLike] = None,
seed: Optional[int] = None,
id: Optional[str] = None,
):
self.seed = seed
super().__init__(wires=wires, id=id)
Expand Down
13 changes: 9 additions & 4 deletions pennylane/ops/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

from pennylane import math as np
from pennylane.operation import AnyWires, Channel
from pennylane.wires import Wires, WiresLike


class AmplitudeDamping(Channel):
Expand Down Expand Up @@ -58,7 +59,8 @@ class AmplitudeDamping(Channel):
num_wires = 1
grad_method = "F"

def __init__(self, gamma, wires, id=None):
def __init__(self, gamma, wires: WiresLike, id=None):
wires = Wires(wires)
super().__init__(gamma, wires=wires, id=id)

@staticmethod
Expand Down Expand Up @@ -563,7 +565,8 @@ class PauliError(Channel):
num_params = 2
"""int: Number of trainable parameters that the operator depends on."""

def __init__(self, operators, p, wires=None, id=None):
def __init__(self, operators, p, wires: WiresLike, id=None):
wires = Wires(wires)
super().__init__(operators, p, wires=wires, id=id)

# check if the specified operators are legal
Expand Down Expand Up @@ -713,7 +716,8 @@ class QubitChannel(Channel):
num_wires = AnyWires
grad_method = None

def __init__(self, K_list, wires=None, id=None):
def __init__(self, K_list, wires: WiresLike, id=None):
wires = Wires(wires)
super().__init__(*K_list, wires=wires, id=id)

# check all Kraus matrices are square matrices
Expand Down Expand Up @@ -744,7 +748,8 @@ def _flatten(self):

# pylint: disable=arguments-differ, unused-argument
@classmethod
def _primitive_bind_call(cls, K_list, wires=None, id=None):
def _primitive_bind_call(cls, K_list, wires: WiresLike, id=None):
wires = Wires(wires)
return super()._primitive_bind_call(*K_list, wires=wires)

@staticmethod
Expand Down
23 changes: 14 additions & 9 deletions pennylane/ops/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
Operation,
SparseMatrixUndefinedError,
)
from pennylane.wires import WiresLike


class Identity(CVObservable, Operation):
Expand Down Expand Up @@ -61,15 +62,16 @@ class Identity(CVObservable, Operation):
ev_order = 1

@classmethod
def _primitive_bind_call(cls, wires=None, **kwargs): # pylint: disable=arguments-differ
wires = [] if wires is None else wires
def _primitive_bind_call(
cls, wires: WiresLike = (), **kwargs
): # pylint: disable=arguments-differ
return super()._primitive_bind_call(wires=wires, **kwargs)

def _flatten(self):
return tuple(), (self.wires, tuple())

def __init__(self, wires=None, id=None):
super().__init__(wires=[] if wires is None else wires, id=id)
def __init__(self, wires: WiresLike = (), id=None):
super().__init__(wires=wires, id=id)
self._hyperparameters = {"n_wires": len(self.wires)}
self._pauli_rep = qml.pauli.PauliSentence({qml.pauli.PauliWord({}): 1.0})

Expand Down Expand Up @@ -308,12 +310,13 @@ def circuit():
grad_method = None

@classmethod
def _primitive_bind_call(cls, phi, wires=None, **kwargs): # pylint: disable=arguments-differ
wires = [] if wires is None else wires
def _primitive_bind_call(
cls, phi, wires: WiresLike = (), **kwargs
): # pylint: disable=arguments-differ
return super()._primitive_bind_call(phi, wires=wires, **kwargs)

def __init__(self, phi, wires=None, id=None):
super().__init__(phi, wires=[] if wires is None else wires, id=id)
def __init__(self, phi, wires: WiresLike = (), id=None):
super().__init__(phi, wires=wires, id=id)

@staticmethod
def compute_eigvals(phi, n_wires=1): # pylint: disable=arguments-differ
Expand Down Expand Up @@ -412,7 +415,9 @@ def compute_diagonalizing_gates(
return []

@staticmethod
def compute_decomposition(phi, wires=None): # pylint:disable=arguments-differ,unused-argument
def compute_decomposition(
phi, wires: WiresLike = ()
): # pylint:disable=arguments-differ,unused-argument
r"""Representation of the operator as a product of other operators (static method).
.. note::
Expand Down
17 changes: 7 additions & 10 deletions pennylane/ops/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

import pennylane as qml
from pennylane.operation import AnyWires, Operation
from pennylane.wires import Wires # pylint: disable=unused-import
from pennylane.wires import Wires, WiresLike


class Barrier(Operation):
Expand All @@ -46,7 +46,8 @@ class Barrier(Operation):
num_wires = AnyWires
par_domain = None

def __init__(self, wires=Wires([]), only_visual=False, id=None):
def __init__(self, wires: WiresLike = (), only_visual=False, id=None):
wires = Wires(wires)
self.only_visual = only_visual
self.hyperparameters["only_visual"] = only_visual
super().__init__(wires=wires, id=id)
Expand Down Expand Up @@ -119,16 +120,12 @@ class WireCut(Operation):
num_wires = AnyWires
grad_method = None

def __init__(self, *params, wires=None, id=None):
if wires == []:
raise ValueError(
f"{self.__class__.__name__}: wrong number of wires. "
f"At least one wire has to be given."
)
super().__init__(*params, wires=wires, id=id)
def __init__(self, wires: WiresLike = (), id=None):
wires = Wires(wires)
super().__init__(wires=wires, id=id)

@staticmethod
def compute_decomposition(wires): # pylint: disable=unused-argument
def compute_decomposition(wires: WiresLike): # pylint: disable=unused-argument
r"""Representation of the operator as a product of other operators (static method).
Since this operator is a placeholder inside a circuit, it decomposes into an empty list.
Expand Down
15 changes: 11 additions & 4 deletions pennylane/ops/op_math/controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from pennylane.capture.capture_diff import create_non_interpreted_prim
from pennylane.compiler import compiler
from pennylane.operation import Operator
from pennylane.wires import Wires
from pennylane.wires import Wires, WiresLike

from .controlled_decompositions import ctrl_decomp_bisect, ctrl_decomp_zyz
from .symbolicop import SymbolicOp
Expand Down Expand Up @@ -175,7 +175,7 @@ def create_controlled_op(op, control, control_values=None, work_wires=None):
# Flatten nested controlled operations to a multi-controlled operation for better
# decomposition algorithms. This includes special cases like CRX, CRot, etc.
if isinstance(op, Controlled):
work_wires = work_wires or []
work_wires = () if work_wires is None else work_wires
return ctrl(
op.base,
control=control + op.control_wires,
Expand Down Expand Up @@ -489,9 +489,16 @@ def _primitive_bind_call(
)

# pylint: disable=too-many-function-args
def __init__(self, base, control_wires, control_values=None, work_wires=None, id=None):
def __init__(
self,
base,
control_wires: WiresLike,
control_values=None,
work_wires: WiresLike = None,
id=None,
):
control_wires = Wires(control_wires)
work_wires = Wires([]) if work_wires is None else Wires(work_wires)
work_wires = Wires(() if work_wires is None else work_wires)

if control_values is None:
control_values = [True] * len(control_wires)
Expand Down
33 changes: 21 additions & 12 deletions pennylane/ops/op_math/controlled_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,16 @@ def _primitive_bind_call(cls, wires, control_values=None, work_wires=None, id=No
)

# pylint: disable=too-many-arguments
def __init__(self, control_wires=None, wires=None, control_values=None, work_wires=None):
def __init__(
self,
control_wires: WiresLike = (),
wires: WiresLike = (),
control_values=None,
work_wires: WiresLike = (),
):
control_wires = Wires(() if control_wires is None else control_wires)
wires = Wires(() if wires is None else wires)
work_wires = Wires(() if work_wires is None else work_wires)

# First raise deprecation warnings regardless of the validity of other arguments
if isinstance(control_values, str):
Expand All @@ -1164,22 +1173,19 @@ def __init__(self, control_wires=None, wires=None, control_values=None, work_wir
"supported in future releases, Use a list of booleans or integers instead.",
qml.PennyLaneDeprecationWarning,
)
if control_wires is not None:
if len(control_wires) > 0:
warnings.warn(
"The control_wires keyword for MultiControlledX is deprecated, and will "
"be removed soon. Use wires = (*control_wires, target_wire) instead.",
UserWarning,
)

if wires is None:
if len(wires) == 0:
raise ValueError("Must specify the wires where the operation acts on")

wires = wires if isinstance(wires, Wires) else Wires(wires)

if control_wires is not None:
if len(control_wires) > 0:
if len(wires) != 1:
raise ValueError("MultiControlledX accepts a single target wire.")
control_wires = Wires(control_wires)
else:
if len(wires) < 2:
raise ValueError(
Expand Down Expand Up @@ -1212,7 +1218,7 @@ def wires(self):

# pylint: disable=unused-argument, arguments-differ
@staticmethod
def compute_matrix(control_wires, control_values=None, **kwargs):
def compute_matrix(control_wires: WiresLike, control_values=None, **kwargs):
r"""Representation of the operator as a canonical matrix in the computational basis (static method).
The canonical matrix is the textbook matrix representation that does not consider wires.
Expand Down Expand Up @@ -1255,7 +1261,9 @@ def matrix(self, wire_order=None):

# pylint: disable=unused-argument, arguments-differ
@staticmethod
def compute_decomposition(wires=None, work_wires=None, control_values=None, **kwargs):
def compute_decomposition(
wires: WiresLike = None, work_wires: WiresLike = None, control_values=None, **kwargs
):
r"""Representation of the operator as a product of other operators (static method).
.. math:: O = O_1 O_2 \dots O_n.
Expand All @@ -1282,6 +1290,7 @@ def compute_decomposition(wires=None, work_wires=None, control_values=None, **kw
Toffoli(wires=[0, 1, 'aux'])]
"""
wires = Wires(() if wires is None else wires)

if len(wires) < 2:
raise ValueError(f"Wrong number of wires. {len(wires)} given. Need at least 2.")
Expand Down Expand Up @@ -1357,7 +1366,7 @@ class CRX(ControlledOp):
name = "CRX"
parameter_frequencies = [(0.5, 1.0)]

def __init__(self, phi, wires, id=None):
def __init__(self, phi, wires: WiresLike, id=None):
# We use type.__call__ instead of calling the class directly so that we don't bind the
# operator primitive when new program capture is enabled
base = type.__call__(qml.RX, phi, wires=wires[1:])
Expand All @@ -1374,7 +1383,7 @@ def _unflatten(cls, data, metadata):
return cls(*data, wires=metadata[0])

@classmethod
def _primitive_bind_call(cls, phi, wires, id=None):
def _primitive_bind_call(cls, phi, wires: WiresLike, id=None):
return cls._primitive.bind(phi, *wires, n_wires=len(wires))

@staticmethod
Expand Down Expand Up @@ -1425,7 +1434,7 @@ def compute_matrix(theta): # pylint: disable=arguments-differ
return qml.math.stack([stack_last(row) for row in matrix], axis=-2)

@staticmethod
def compute_decomposition(phi, wires): # pylint: disable=arguments-differ
def compute_decomposition(phi, wires: WiresLike): # pylint: disable=arguments-differ
r"""Representation of the operator as a product of other operators (static method). :
.. math:: O = O_1 O_2 \dots O_n.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/ops/qubit/non_parametric_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def pauli_rep(self):
)
return self._pauli_rep

def __init__(self, wires: Optional[WiresLike] = None, id: Optional[str] = None):
def __init__(self, wires: WiresLike, id: Optional[str] = None):
super().__init__(wires=wires, id=id)

def label(
Expand Down
Loading

0 comments on commit 922f808

Please sign in to comment.