Skip to content

Commit

Permalink
Merge branch 'master' into autograph_ctrl_flow
Browse files Browse the repository at this point in the history
  • Loading branch information
lillian542 authored Oct 12, 2024
2 parents 42ce1e8 + 9ac2504 commit d3a807c
Show file tree
Hide file tree
Showing 76 changed files with 1,702 additions and 458 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/module-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Validate module imports

on:
pull_request:
types:
- opened
- reopened
- synchronize
- ready_for_review

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:

tach:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5

with:
python-version: "3.10"

- name: Install dependencies
run: pip install tach==0.13.1

- name: Run tach
run: |
tach report pennylane/labs
tach check
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
upload-stable-deps:
needs: tests
runs-on: ubuntu-latest
if: ${{ github.event_name == 'push' }}
if: ${{ github.event_name == 'schedule' }}
steps:
- name: Checkout
uses: actions/checkout@v3
Expand Down
4 changes: 4 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ repos:
"--filter-files",
]
files: ^(pennylane/|tests/)
- repo: https://github.com/gauge-sh/tach-pre-commit
rev: v0.13.1
hooks:
- id: tach
- repo: local
hooks:
- id: pylint
Expand Down
116 changes: 114 additions & 2 deletions doc/introduction/compiling_circuits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ quantum functions of optimized circuits:
~pennylane.transforms.remove_barrier
~pennylane.transforms.single_qubit_fusion
~pennylane.transforms.undo_swaps
~pennylane.transforms.decompose

:html:`</div>`

Expand Down Expand Up @@ -173,6 +174,8 @@ controlled gates and cancel adjacent inverses, we could do:
.. code-block:: python
from pennylane.transforms import commute_controlled, cancel_inverses
from functools import partial
pipeline = [commute_controlled, cancel_inverses]
@partial(qml.compile, pipeline=pipeline)
Expand Down Expand Up @@ -208,8 +211,8 @@ For more details on :func:`~.pennylane.compile` and the available compilation tr
`the compilation documentation
<../code/qml_transforms.html#transforms-for-circuit-compilation>`_.

Custom decompositions
---------------------
Custom Operator Decomposition
-----------------------------

PennyLane decomposes gates unknown to the device into other, "lower-level" gates. As a user, you may want to fine-tune this mechanism. For example, you may wish your circuit to use different fundamental gates.

Expand Down Expand Up @@ -262,6 +265,115 @@ according to our specifications:
If the custom decomposition is only supposed to be used in a specific code context,
a separate context manager :func:`~.pennylane.transforms.set_decomposition` can be used.

Circuit Decomposition
---------------------

When compiling a circuit it is often beneficial to decompose the circuit into a set of basis gates.
To do this, we can use the :func:`~.pennylane.transforms.decompose` function, which allows the decomposition of
circuits into a set of gates defined either by their name, type, or by a set of rules they must follow.

Using a gate set
****************

The example below demonstrates how a three-wire circuit can be decomposed using a pre-defined set of gates:

.. code-block:: python
from pennylane.transforms import decompose
from functools import partial
dev = qml.device('default.qubit')
allowed_gates = {qml.Toffoli, qml.RX, qml.RZ}
@partial(decompose, gate_set=allowed_gates)
@qml.qnode(dev)
def circuit():
qml.Hadamard(wires=[0])
qml.Toffoli(wires=[0,1,2])
return qml.expval(qml.Z(0))
With the Hadamard gate not in our gate set, it will be decomposed into the respective rotation gate operators.

>>> print(qml.draw(circuit)())
0: ──RZ(1.57)──RX(1.57)──RZ(1.57)─╭●─┤ <Z>
1: ───────────────────────────────├●─┤
2: ───────────────────────────────╰X─┤

Using a gate rule
*****************

The example below demonstrates how a three-wire circuit can be decomposed using a rule that decomposes the circuit down into single or two-qubit gates:

.. code-block:: python
@partial(decompose, gate_set=lambda op: len(op.wires)<=2)
@qml.qnode(dev)
def circuit():
qml.Toffoli(wires=[0,1,2])
return qml.expval(qml.Z(0))
>>> print(qml.draw(circuit)())
0: ───────────╭●───────────╭●────╭●──T──╭●─┤ <Z>
1: ────╭●─────│─────╭●─────│───T─╰X──T†─╰X─┤
2: ──H─╰X──T†─╰X──T─╰X──T†─╰X──T──H────────┤

Decomposition in stages
***********************

You can use the ``max_expansion`` kwarg to have control over the number
of decomposition stages applied to the circuit. By default, the function will decompose
the circuit until the desired gate set is reached.

The example below shows how the user can visualize the decomposition.
We begin with creating a :class:`~.pennylane.QuantumPhaseEstimation` circuit:

.. code-block:: python
phase = 1
target_wires = [0]
unitary = qml.RX(phase, wires=0).matrix()
n_estimation_wires = 3
estimation_wires = range(1, n_estimation_wires + 1)
@qml.qnode(qml.device('default.qubit'))
def circuit():
# Start in the |+> eigenstate of the unitary
qml.Hadamard(wires=target_wires)
qml.QuantumPhaseEstimation(
unitary,
target_wires=target_wires,
estimation_wires=estimation_wires,
)
From here, we can iterate through the stages of decomposition:

>>> print(qml.draw(decompose(circuit, max_expansion=0))())
0: ──H─╭QuantumPhaseEstimation─┤
1: ────├QuantumPhaseEstimation─┤
2: ────├QuantumPhaseEstimation─┤
3: ────╰QuantumPhaseEstimation─┤

>>> print(qml.draw(decompose(circuit, max_expansion=1))())
0: ──H─╭U(M0)⁴─╭U(M0)²─╭U(M0)¹───────┤
1: ──H─╰●──────│───────│───────╭QFT†─┤
2: ──H─────────╰●──────│───────├QFT†─┤
3: ──H─────────────────╰●──────╰QFT†─┤

>>> print(qml.draw(decompose(circuit, max_expansion=2))())
0: ──H──RZ(11.00)──RY(1.14)─╭X──RY(-1.14)──RZ(-9.42)─╭X──RZ(-1.57)──RZ(1.57)──RY(1.00)─╭X──RY(-1.00)
1: ──H──────────────────────╰●───────────────────────╰●────────────────────────────────│────────────
2: ──H─────────────────────────────────────────────────────────────────────────────────╰●───────────
3: ──H──────────────────────────────────────────────────────────────────────────────────────────────
───RZ(-6.28)─╭X──RZ(4.71)──RZ(1.57)──RY(0.50)─╭X──RY(-0.50)──RZ(-6.28)─╭X──RZ(4.71)─────────────────
─────────────│────────────────────────────────│────────────────────────│──╭SWAP†────────────────────
─────────────╰●───────────────────────────────│────────────────────────│──│─────────────╭(Rϕ(1.57))†
──────────────────────────────────────────────╰●───────────────────────╰●─╰SWAP†─────H†─╰●──────────
────────────────────────────────────┤
──────╭(Rϕ(0.79))†─╭(Rϕ(1.57))†──H†─┤
───H†─│────────────╰●───────────────┤
──────╰●────────────────────────────┤

Circuit cutting
---------------

Expand Down
46 changes: 45 additions & 1 deletion doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@

<h3>New features since last release</h3>

* Function is added for user-facing circuit decomposition.
* Introduced `sample_probs` function for the `qml.devices.qubit` and `qml.devices.qutrit_mixed` modules:
- This function takes probability distributions as input and returns sampled outcomes.
- Simplifies the sampling process by separating it from other operations in the measurement chain.
- Improves modularity: The same code can be easily adapted for other devices (e.g., a potential `default_mixed` device).
- Enhances maintainability by isolating the sampling logic.
[(#6354)](https://github.com/PennyLaneAI/pennylane/pull/6354)

* `qml.transforms.decompose` is added for stepping through decompositions to a target gate set.
[(#6334)](https://github.com/PennyLaneAI/pennylane/pull/6334)

* Added `process_density_matrix` implementations to 5 `StateMeasurement` subclasses:
Expand Down Expand Up @@ -38,6 +45,13 @@

<h3>Improvements 🛠</h3>

* Module-level sandboxing added to `qml.labs` via pre-commit hooks.
[(#6369)](https://github.com/PennyLaneAI/pennylane/pull/6369)

* `qml.matrix` now works with empty objects (such as empty tapes, `QNode`s and quantum functions that do
not call operations, single operators with empty decompositions).
[(#6347)](https://github.com/PennyLaneAI/pennylane/pull/6347)

* PennyLane is now compatible with NumPy 2.0.
[(#6061)](https://github.com/PennyLaneAI/pennylane/pull/6061)
[(#6258)](https://github.com/PennyLaneAI/pennylane/pull/6258)
Expand All @@ -57,10 +71,20 @@
`trainable_params` as keyword arguments. If any of these are passed when copying a
tape, the specified attributes will replace the copied attributes on the new tape.
[(#6285)](https://github.com/PennyLaneAI/pennylane/pull/6285)
[(#6363)](https://github.com/PennyLaneAI/pennylane/pull/6363)

* The `Hermitian` operator now has a `compute_sparse_matrix` implementation.
[(#6225)](https://github.com/PennyLaneAI/pennylane/pull/6225)

* `qml.QutritBasisStatePreparation` is now JIT compatible.
[(#6308)](https://github.com/PennyLaneAI/pennylane/pull/6308)

* `qml.AmplitudeAmplification` is now compatible with QJIT.
[(#6306)](https://github.com/PennyLaneAI/pennylane/pull/6306)

* The quantum arithmetic templates are now QJIT compatible.
[(#6307)](https://github.com/PennyLaneAI/pennylane/pull/6307)

* The `qml.Qubitization` template is now QJIT compatible.
[(#6305)](https://github.com/PennyLaneAI/pennylane/pull/6305)

Expand All @@ -74,6 +98,9 @@
unprocessed diagonalizing gates.
[(#6290)](https://github.com/PennyLaneAI/pennylane/pull/6290)

* A more sensible error message is raised from a `RecursionError` encountered when accessing properties and methods of a nested `CompositeOp` or `SProd`.
[(#6375)](https://github.com/PennyLaneAI/pennylane/pull/6375)

<h4>Capturing and representing hybrid programs</h4>

* `qml.wires.Wires` now accepts JAX arrays as input. Furthermore, a `FutureWarning` is no longer raised in `JAX 0.4.30+`
Expand Down Expand Up @@ -133,6 +160,9 @@

<h3>Breaking changes 💔</h3>

* `AllWires` validation in `QNode.construct` has been removed.
[(#6373)](https://github.com/PennyLaneAI/pennylane/pull/6373)

* The `simplify` argument in `qml.Hamiltonian` and `qml.ops.LinearCombination` has been removed.
Instead, `qml.simplify()` can be called on the constructed operator.
[(#6279)](https://github.com/PennyLaneAI/pennylane/pull/6279)
Expand Down Expand Up @@ -179,6 +209,7 @@
`qml.ops.LinearCombination`; this behaviour is not deprecated. For more information, check out the
[updated operator troubleshooting page](https://docs.pennylane.ai/en/stable/news/new_opmath.html).
[(#6287)](https://github.com/PennyLaneAI/pennylane/pull/6287)
[(#6365)](https://github.com/PennyLaneAI/pennylane/pull/6365)

* `qml.pauli.PauliSentence.hamiltonian` and `qml.pauli.PauliWord.hamiltonian` are deprecated. Instead, please use
`qml.pauli.PauliSentence.operation` and `qml.pauli.PauliWord.operation` respectively.
Expand Down Expand Up @@ -238,8 +269,17 @@
* Removed ambiguity in error raised by the `PauliRot` class.
[(#6298)](https://github.com/PennyLaneAI/pennylane/pull/6298)

* Renamed an incorrectly named test in `test_pow_ops.py`.
[(#6388)](https://github.com/PennyLaneAI/pennylane/pull/6388)

<h3>Bug fixes 🐛</h3>

* `default.qutrit` now returns integer samples.
[(#6385)](https://github.com/PennyLaneAI/pennylane/pull/6385)

* `adjoint_metric_tensor` now works with circuits containing state preparation operations.
[(#6358)](https://github.com/PennyLaneAI/pennylane/pull/6358)

* `quantum_fisher` now respects the classical Jacobian of QNodes.
[(#6350)](https://github.com/PennyLaneAI/pennylane/pull/6350)

Expand Down Expand Up @@ -284,6 +324,9 @@
* Fixes a test after updating to the nightly version of Catalyst.
[(#6362)](https://github.com/PennyLaneAI/pennylane/pull/6362)

* Fixes a bug where `CommutingEvolution` with a trainable `Hamiltonian` cannot be differentiated using parameter shift.
[(#6372)](https://github.com/PennyLaneAI/pennylane/pull/6372)

<h3>Contributors ✍️</h3>

This release contains contributions from (in alphabetical order):
Expand All @@ -304,5 +347,6 @@ William Maxwell,
Erick Ochoa Lopez,
Lee J. O'Riordan,
Mudit Pandey,
Andrija Paurevic,
David Wierichs,
Andrija Paurevic,
2 changes: 1 addition & 1 deletion pennylane/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.39.0-dev31"
__version__ = "0.39.0-dev34"
3 changes: 2 additions & 1 deletion pennylane/data/attributes/operator/operator.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ def _hdf5_to_ops(self, bind: HDF5Group) -> list[Operator]:

op_cls = self._supported_ops_dict()[op_class_name]
if op_cls is Tensor:
ops.append(Tensor(*self._hdf5_to_ops(bind[op_key])))
prod_op = qml.ops.Prod if qml.operation.active_new_opmath() else Tensor
ops.append(prod_op(*self._hdf5_to_ops(bind[op_key])))
elif op_cls in (qml.ops.Hamiltonian, qml.ops.LinearCombination):
ops.append(
qml.Hamiltonian(
Expand Down
3 changes: 2 additions & 1 deletion pennylane/devices/_qubit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,8 @@ def statistics(

elif isinstance(m, SampleMP):
samples = self.sample(obs, shot_range=shot_range, bin_size=bin_size, counts=False)
result = self._asarray(qml.math.squeeze(samples))
dtype = int if isinstance(obs, SampleMP) else None
result = self._asarray(qml.math.squeeze(samples), dtype=dtype)

elif isinstance(m, CountsMP):
result = self.sample(m, shot_range=shot_range, bin_size=bin_size, counts=True)
Expand Down
7 changes: 4 additions & 3 deletions pennylane/devices/qubit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@
measure
measure_with_samples
sample_state
sample_probs
simulate
adjoint_jacobian
adjoint_jvp
adjoint_vjp
"""

from .apply_operation import apply_operation
from .adjoint_jacobian import adjoint_jacobian, adjoint_jvp, adjoint_vjp
from .apply_operation import apply_operation
from .initialize_state import create_initial_state
from .measure import measure
from .sampling import sample_state, measure_with_samples
from .simulate import simulate, get_final_state, measure_final_state
from .sampling import measure_with_samples, sample_probs, sample_state
from .simulate import get_final_state, measure_final_state, simulate
Loading

0 comments on commit d3a807c

Please sign in to comment.