Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 5 additions & 21 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,22 +154,6 @@
overlapping qubits may still be merged into one layer.
[(#2858)](https://github.com/PennyLaneAI/catalyst/pull/2858)

* The :func:`~.passes.ppm_specs` now report circuit depth as ``depth``
(layer count) and ``depth_type`` (``0`` = commuting ops on overlapping qubits may share a
layer; ``1`` = only ops with disjoint qubit support may share a layer). The Python API accepts
``only_disjoint_qubit=True`` to run ``ppm-specs{disjoint-qubit=true}``. AOT ``ppm_specs`` no
longer requires an explicit pipeline and no longer mixes MLIR into the JSON output.
[(#2863)](https://github.com/PennyLaneAI/catalyst/pull/2863)

* The ``depth`` field reported by :func:`~.passes.ppm_specs` is now the worst-case depth
across ``scf.if`` and ``scf.index_switch`` branches (taking the maximum over all branches)
and across statically-bounded ``scf.for`` loops (multiplied by the trip count).
Previously, branches were counted sequentially and PBC ops inside ``scf.for`` produced an
error. ``scf.while`` and dynamically-bounded ``scf.for`` still produce an error.
[(#2876)](https://github.com/PennyLaneAI/catalyst/pull/2876)
[(#2877)](https://github.com/PennyLaneAI/catalyst/pull/2877)
[(#2879)](https://github.com/PennyLaneAI/catalyst/pull/2879)

* Global toggles, ``compile_without_static_conditionals`` and ``compile_without_static_loops`` have
been added to control the capture behaviour for ``catalyst``/``pennylane`` ``cond`` and
``for_loop`` instructions. Setting the toggle to ``True`` will automatically remove the respective
Expand Down Expand Up @@ -259,6 +243,11 @@

<h3>Breaking changes 💔</h3>

* Removes :func:`~.passes.ppm_specs` and the ``--ppm-specs`` MLIR pass. Use :func:`~.specs` and
the ``ResourceAnalysis`` pass instead for PPR/PPM resource counts and PBC layer depth
(``any_commuting_depth`` / ``qubit_disjoint_depth``) with the same functionality.
[(#XXXX)](https://github.com/PennyLaneAI/catalyst/pull/XXXX)

* Removes the non-graph decomposition fallback when `capture=True` is enabled.
[(#3058)](https://github.com/PennyLaneAI/catalyst/pull/3058/)

Expand Down Expand Up @@ -325,11 +314,6 @@
* Fix memory bugs in the PBC passes.
[(#2918)](https://github.com/PennyLaneAI/catalyst/pull/2918)

* Fixed incorrect ``depth`` in :func:`~.passes.ppm_specs` when a ``quantum.extract`` appeared
after a PBC op but read from a register not updated by that op. Layer grouping now checks
data dependencies through insert to extract chains instead of textual op ordering.
[(#2884)](https://github.com/PennyLaneAI/catalyst/pull/2884)

* Fixed the assembly format for `quantum.adjoint` when it has no quantum operands/results.
[(#2938)](https://github.com/PennyLaneAI/catalyst/pull/2938)

Expand Down
2 changes: 0 additions & 2 deletions frontend/catalyst/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
merge_rotations,
parity_synth,
ppm_compilation,
ppm_specs,
ppr_to_mbqc,
ppr_to_ppm,
reduce_t_depth,
Expand All @@ -64,7 +63,6 @@
"ppr_to_ppm",
"merge_ppr_ppm",
"ppm_compilation",
"ppm_specs",
"reduce_t_depth",
"decompose_arbitrary_ppr",
"combine_global_phases",
Expand Down
96 changes: 0 additions & 96 deletions frontend/catalyst/passes/builtin_passes.py
Original file line number Diff line number Diff line change
Expand Up @@ -1432,102 +1432,6 @@ def circuit():
)


def ppm_specs(fn, only_disjoint_qubit: bool = False):
r"""This function returns following Pauli product rotation (PPR) and Pauli product measurement (PPM)
specs in a dictionary:

- Pi/4 PPR (count the number of clifford PPRs)
- Pi/8 PPR (count the number of non-clifford PPRs)
- Pi/2 PPR (count the number of classical PPRs)
- Max weight for pi/8 PPRs
- Max weight for pi/4 PPRs
- Max weight for pi/2 PPRs
- Number of logical qubits
- Number of PPMs
- ``depth``: number of PBC layers
- ``depth_type``: ``0`` if commuting ops on overlapping qubits may share a layer;
``1`` if only ops with disjoint qubit support may share a layer

.. note::

It is recommended to use :func:`pennylane.specs` instead of ``ppm_specs`` to retrieve
resource counts of PPR-PPM workflows.

When there is control flow, this function can count the above statistics inside for loops with
a statically known number of iterations. For all other cases, including dynamically sized for
loops, and any conditionals and while loops, this pass exits with failure.

Args:
fn (QJIT): qjit-decorated function for which ``ppm_specs`` need to be printed.
only_disjoint_qubit (bool): If ``True``, depth is computed using disjoint-qubit layering
(``depth_type`` 1). If ``False`` (default), commuting ops on overlapping qubits may
share a layer (``depth_type`` 0). Passed to the ``ppm-specs`` MLIR pass as
``disjoint-qubit``.

Returns:
dict: A Python dictionary containing PPM specs of all functions in ``fn``.

**Example**

.. code-block:: python

import pennylane as qp
import catalyst
from catalyst.passes import ppm_specs, to_ppr

@qp.qjit(target="mlir")
@to_ppr
@qp.qnode(qp.device("lightning.qubit", wires=2))
def f():
qp.H(0)
qp.S(1)
qp.T(0)
qp.CNOT(wires=[0, 1])
return qp.expval(qp.Z(0))

print(ppm_specs(f))
print(ppm_specs(f, only_disjoint_qubit=True))

Example output:

.. code-block:: pycon

{'f_0': {'depth': 4, 'depth_type': 0, 'logical_qubits': 2, 'max_weight_pi4': 2,
'max_weight_pi8': 1, 'pi4_ppr': 7, 'pi8_ppr': 1}}
{'f_0': {'depth': 7, 'depth_type': 1, 'logical_qubits': 2, 'max_weight_pi4': 2,
'max_weight_pi8': 1, 'pi4_ppr': 7, 'pi8_ppr': 1}}
"""

if fn.mlir_module is not None:
# aot mode: e.g: setting target="mlir", pipeline="..."
new_options = copy.copy(fn.compile_options)
if new_options.pipelines is None:
new_options.pipelines = [
(name, list(passes)) for name, passes in new_options.get_pipelines()
]

# add ppm-spec pass at the end to existing pipeline
_, pass_list = new_options.pipelines[0] # first pipeline runs the user passes
# check if ppm-specs is already in the pass list
ppm_specs_pass = "ppm-specs{disjoint-qubit=true}" if only_disjoint_qubit else "ppm-specs"
pass_list[:] = [p for p in pass_list if not p.startswith("ppm-specs")] + [ppm_specs_pass]

new_options = _options_to_cli_flags(new_options)
# redirect output to devnull to avoid printing the MLIR
raw_result = _quantum_opt(*new_options, "-o", os.devnull, stdin=str(fn.mlir_module))

try:
return json.loads(raw_result) # validate before returning
except (json.JSONDecodeError, ValueError) as e: # pragma: nocover
raise CompileError(
"Invalid json format encountered in ppm_specs. "
f"Expected valid JSON but got {raw_result}"
) from e

else:
raise NotImplementedError("PPM passes only support AOT (Ahead-Of-Time) compilation mode.")


def reduce_t_depth_setup_inputs():
r"""A quantum compilation pass that reduces the depth and count of non-Clifford Pauli product
rotation (PPR, :math:`P(\theta) = \exp(-iP\theta)`) operators (e.g., ``T`` gates) by commuting
Expand Down
Loading
Loading