Skip to content

Commit

Permalink
[Transform doc] Separate qcut (#4819)
Browse files Browse the repository at this point in the history
**Context:**
We want to make sure that qcut has a good place in the documentation and
in PennyLane.

**Description of the Change:**
- qcut has its own folder
- qcut appears in API doc
- remove `qcut.py` file
- rename `montecarlo.py` to `cutcircuit_mc.py`

**Benefits:**
Better visibility of qcut (both in the project and in the docs).

---------

Co-authored-by: Tom Bromley <[email protected]>
Co-authored-by: Josh Izaac <[email protected]>
  • Loading branch information
3 people authored Nov 28, 2023
1 parent 7cb7b7a commit 9781f11
Show file tree
Hide file tree
Showing 18 changed files with 316 additions and 303 deletions.
8 changes: 8 additions & 0 deletions doc/code/qml_qcut.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
qml.qcut
========


.. currentmodule:: pennylane.qcut


.. automodule:: pennylane.qcut
1 change: 1 addition & 0 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ PennyLane is **free** and **open source**, released under the Apache License, Ve
code/qml_ops_op_math
code/qml_pauli
code/qml_pulse
code/qml_qcut
code/qml_qinfo
code/qml_resource
code/qml_shadows
Expand Down
4 changes: 2 additions & 2 deletions doc/introduction/inspecting_circuits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,12 @@ False


Another way to construct the "causal" DAG of a circuit is to use the
:func:`~pennylane.transforms.qcut.tape_to_graph` function used by the ``qcut`` module. This
:func:`~pennylane.qcut.tape_to_graph` function used by the ``qcut`` module. This
function takes a quantum tape and creates a ``MultiDiGraph`` instance from the ``networkx`` python package.

Using the above example, we get:

>>> g2 = qml.transforms.qcut.tape_to_graph(tape)
>>> g2 = qml.qcut.tape_to_graph(tape)
>>> type(g2)
<class 'networkx.classes.multidigraph.MultiDiGraph'>
>>> for k, v in g2.adjacency():
Expand Down
7 changes: 7 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@

<h3>Breaking changes 💔</h3>

* The transforms submodule `qml.transforms.qcut` becomes its own module `qml.qcut`.
[(#4819)](https://github.com/PennyLaneAI/pennylane/pull/4819)

* The decomposition of `GroverOperator` now has an additional global phase operation.
[(#4666)](https://github.com/PennyLaneAI/pennylane/pull/4666)

Expand Down Expand Up @@ -263,6 +266,9 @@

<h3>Documentation 📝</h3>

* Documentation for QCut was move to its own API page `qml.qcut`.
[(#4819)](https://github.com/PennyLaneAI/pennylane/pull/4819)

* Documentation page for `qml.measurements` now links top-level accessible functions (e.g. `qml.expval`)
to their top-level pages (rather than their module-level pages, eg. `qml.measurements.expval`).
[(#4750)](https://github.com/PennyLaneAI/pennylane/pull/4750)
Expand Down Expand Up @@ -353,6 +359,7 @@ Josh Izaac,
Emiliano Godinez Ramirez,
Ankit Khandelwal,
Christina Lee,
Romain Moyard,
Vincent Michaud-Rioux,
Anurav Modak,
Mudit Pandey,
Expand Down
3 changes: 1 addition & 2 deletions pennylane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,6 @@
batch_input,
batch_transform,
batch_partial,
cut_circuit,
cut_circuit_mc,
compile,
defer_measurements,
metric_tensor,
Expand Down Expand Up @@ -119,6 +117,7 @@
from pennylane.vqe import ExpvalCost
from pennylane.debugging import snapshots
from pennylane.shadows import ClassicalShadow
from pennylane.qcut import cut_circuit, cut_circuit_mc
import pennylane.pulse

import pennylane.fourier
Expand Down
142 changes: 142 additions & 0 deletions pennylane/qcut/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Copyright 2018-2021 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module contains quantum function transforms for cutting quantum circuits.
.. currentmodule:: pennylane
Overview
--------
This module defines transform functions for circuit cutting. This allows
for 'cutting' (or splitting) of large circuits into smaller circuits, to allow
them to be executed on devices that have a restricted number of qubits.
Transforms for circuit cutting
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. autosummary::
:toctree: api
~cut_circuit
~cut_circuit_mc
Utility functions
~~~~~~~~~~~~~~~~~
There are also low-level functions that can be used to build up the circuit cutting functionalities:
.. autosummary::
:toctree: api
~qcut.tape_to_graph
~qcut.replace_wire_cut_nodes
~qcut.fragment_graph
~qcut.graph_to_tape
~qcut.expand_fragment_tape
~qcut.expand_fragment_tapes_mc
~qcut.qcut_processing_fn
~qcut.qcut_processing_fn_sample
~qcut.qcut_processing_fn_mc
~qcut.CutStrategy
~qcut.kahypar_cut
~qcut.place_wire_cuts
~qcut.find_and_place_cuts
Cutting Circuits
----------------
Circuit cutting can allow you to replace a circuit with ``N`` wires by a set
of circuits with less than ``N`` wires (see also
`Peng et. al <https://arxiv.org/abs/1904.00102>`_). This comes
with a cost: the smaller circuits require a greater number of device
executions to be evaluated.
In PennyLane, circuit cutting for circuits that terminate in expectation values
can be activated by positioning :class:`~.pennylane.WireCut` operators at the
desired cut locations, and by decorating the QNode with
the :func:`~.pennylane.cut_circuit` transform.
Cut circuits remain fully differentiable, and the resulting circuits can be
executed on parallel devices if available. Please see the
:func:`~.pennylane.cut_circuit` documentation for more details.
.. note::
Simulated quantum circuits that produce samples can be cut using
the :func:`~.pennylane.cut_circuit_mc`
transform, which is based on the Monte Carlo method.
Automatic cutting
-----------------
PennyLane also has experimental support for automatic cutting of circuits ---
that is, the ability to determine optimum cut location without explicitly
placing :class:`~.pennylane.WireCut` operators. This can be enabled by using the
``auto_cutter`` keyword argument of :func:`~.pennylane.cut_circuit`; refer to the
function documentation for more details.
"""

from .utils import (
replace_wire_cut_node,
replace_wire_cut_nodes,
fragment_graph,
find_and_place_cuts,
place_wire_cuts,
_remove_existing_cuts,
_get_optim_cut,
_is_valid_cut,
MeasureNode,
PrepareNode,
_prep_one_state,
_prep_zero_state,
_prep_plus_state,
_prep_minus_state,
_prep_iplus_state,
_prep_iminus_state,
)
from .tapes import (
graph_to_tape,
tape_to_graph,
expand_fragment_tape,
_qcut_expand_fn,
_get_measurements,
_find_new_wire,
_add_operator_node,
)
from .cutcircuit import cut_circuit, _cut_circuit_expand
from .cutcircuit_mc import (
cut_circuit_mc,
_cut_circuit_mc_expand,
expand_fragment_tapes_mc,
MC_MEASUREMENTS,
MC_STATES,
_identity,
_pauliX,
_pauliY,
_pauliZ,
)
from .processing import (
qcut_processing_fn,
qcut_processing_fn_sample,
qcut_processing_fn_mc,
contract_tensors,
_process_tensor,
_to_tensors,
_reshape_results,
_get_symbol,
)
from .kahypar import kahypar_cut, _graph_to_hmetis
from .cutstrategy import CutStrategy
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,14 @@ def circuit(x):
.. autosummary::
:toctree:
~transforms.qcut.tape_to_graph
~transforms.qcut.find_and_place_cuts
~transforms.qcut.replace_wire_cut_nodes
~transforms.qcut.fragment_graph
~transforms.qcut.graph_to_tape
~transforms.qcut.expand_fragment_tape
~transforms.qcut.qcut_processing_fn
~transforms.qcut.CutStrategy
~qcut.tape_to_graph
~qcut.find_and_place_cuts
~qcut.replace_wire_cut_nodes
~qcut.fragment_graph
~qcut.graph_to_tape
~qcut.expand_fragment_tape
~qcut.qcut_processing_fn
~qcut.CutStrategy
The following shows how these elementary steps are combined as part of the
``cut_circuit()`` transform.
Expand Down Expand Up @@ -233,7 +233,7 @@ def circuit(x):
To cut the circuit, we first convert it to its graph representation:
>>> graph = qml.transforms.qcut.tape_to_graph(tape)
>>> graph = qml.qcut.tape_to_graph(tape)
.. figure:: ../../_static/qcut_graph.svg
:align: center
Expand Down Expand Up @@ -261,19 +261,19 @@ def circuit(x):
measurements = [qml.expval(qml.pauli.string_to_pauli_word("ZZZ"))]
uncut_tape = qml.tape.QuantumTape(ops, measurements)
>>> cut_graph = qml.transforms.qcut.find_and_place_cuts(
... graph = qml.transforms.qcut.tape_to_graph(uncut_tape),
... cut_strategy = qml.transforms.qcut.CutStrategy(max_free_wires=2),
>>> cut_graph = qml.qcut.find_and_place_cuts(
... graph = qml.qcut.tape_to_graph(uncut_tape),
... cut_strategy = qml.qcut.CutStrategy(max_free_wires=2),
... )
>>> print(qml.transforms.qcut.graph_to_tape(cut_graph).draw())
>>> print(qml.qcut.graph_to_tape(cut_graph).draw())
0: ──RX─╭●──RY────┤ ╭<Z@Z@Z>
1: ──RY─╰Z──//─╭●─┤ ├<Z@Z@Z>
2: ──RX────────╰Z─┤ ╰<Z@Z@Z>
Our next step is to remove the :class:`~.WireCut` nodes in the graph and replace with
:class:`~.MeasureNode` and :class:`~.PrepareNode` pairs.
>>> qml.transforms.qcut.replace_wire_cut_nodes(graph)
>>> qml.qcut.replace_wire_cut_nodes(graph)
The :class:`~.MeasureNode` and :class:`~.PrepareNode` pairs are placeholder operations that
allow us to cut the circuit graph and then iterate over measurement and preparation
Expand All @@ -282,11 +282,11 @@ def circuit(x):
`communication_graph <https://en.wikipedia.org/wiki/Quotient_graph>`__
detailing the connectivity between the components.
>>> fragments, communication_graph = qml.transforms.qcut.fragment_graph(graph)
>>> fragments, communication_graph = qml.qcut.fragment_graph(graph)
We now convert the ``fragments`` back to :class:`~.QuantumTape` objects
>>> fragment_tapes = [qml.transforms.qcut.graph_to_tape(f) for f in fragments]
>>> fragment_tapes = [qml.qcut.graph_to_tape(f) for f in fragments]
The circuit fragments can now be visualized:
Expand All @@ -308,7 +308,7 @@ def circuit(x):
.. code-block::
expanded = [qml.transforms.qcut.expand_fragment_tape(t) for t in fragment_tapes]
expanded = [qml.qcut.expand_fragment_tape(t) for t in fragment_tapes]
configurations = []
prepare_nodes = []
Expand Down Expand Up @@ -353,7 +353,7 @@ def circuit(x):
output via a tensor network contraction
>>> results = qml.execute(tapes, dev, gradient_fn=None)
>>> qml.transforms.qcut.qcut_processing_fn(
>>> qml.qcut.qcut_processing_fn(
... results,
... communication_graph,
... prepare_nodes,
Expand Down
Loading

0 comments on commit 9781f11

Please sign in to comment.