Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qcut sampling template expansion #2399

Merged
merged 73 commits into from
Apr 6, 2022
Merged

Conversation

anthayes92
Copy link
Contributor

Context:
A circuit containing sample measurements can be cut using cut_circuit_mc. Here we add an expansion function to the transform that allows cutting support for circuits that contain WireCut operations nested in operations or sub-tapes.

Similar to the expansion function added to cut_circuit in #2340

anthayes92 and others added 30 commits March 11, 2022 18:51
Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
…ithub.com:PennyLaneAI/pennylane into qcut-sample-subgraphs-to-fragment-tape-conversion
Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
Co-authored-by: Tom Bromley <49409390+trbromley@users.noreply.github.com>
@anthayes92 anthayes92 changed the base branch from master to qcut-cut-circuit-mc-transform March 31, 2022 18:50
@github-actions
Copy link
Contributor

Hello. You may have forgotten to update the changelog!
Please edit doc/releases/changelog-dev.md with:

  • A one-to-two sentence description of the change. You may include a small working example for new features.
  • A link back to this PR.
  • Your name (or GitHub username) in the contributors section.

@codecov
Copy link

codecov bot commented Mar 31, 2022

Codecov Report

Merging #2399 (1eb31b8) into master (3a519bf) will increase coverage by 0.00%.
The diff coverage is 100.00%.

@@           Coverage Diff           @@
##           master    #2399   +/-   ##
=======================================
  Coverage   99.45%   99.45%           
=======================================
  Files         244      244           
  Lines       18971    18976    +5     
=======================================
+ Hits        18867    18872    +5     
  Misses        104      104           
Impacted Files Coverage Δ
pennylane/transforms/qcut.py 100.00% <100.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3a519bf...1eb31b8. Read the comment docs.

@anthayes92
Copy link
Contributor Author

[sc-16859]

Comment on lines 1306 to 1333
def _qcut_expand_fn_mc(
tape: QuantumTape,
shots: Optional[int] = None,
device_wires: Optional[Wires] = None,
classical_processing_fn: Optional[callable] = None,
max_depth: int = 1,
):
"""Expansion function for sample-based circuit cutting.

Expands operations until reaching a depth that includes :class:`~.WireCut` operations.
"""
# pylint: disable=unused-argument
for op in tape.operations:
if isinstance(op, WireCut):
return tape

if max_depth > 0:
return cut_circuit_mc.expand_fn(tape.expand(), max_depth=max_depth - 1)

raise ValueError(
"No WireCut operations found in the circuit. Consider increasing the max_depth value if "
"operations or nested tapes contain WireCut operations."
)


cut_circuit_mc.expand_fn = _qcut_expand_fn_mc


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works but I'm not sure if it makes sense to have _qcut_expand_fn and _qcut_expand_fn_mc be the same function with repeated code. How about:

def _qcut_expand_fn(
    tape: QuantumTape,
    max_depth: int = 1,
):
    """Expansion function for sample-based circuit cutting.
    Expands operations until reaching a depth that includes :class:`~.WireCut` operations.
    """
    for op in tape.operations:
        if isinstance(op, WireCut):
            return tape

    if max_depth > 0:
        return _qcut_expand_fn(tape.expand(), max_depth=max_depth - 1)

    raise ValueError(
        "No WireCut operations found in the circuit. Consider increasing the max_depth value if "
        "operations or nested tapes contain WireCut operations."
    )


def cut_circuit_expand(
    tape: QuantumTape,
    use_opt_einsum: bool = False,
    device_wires: Optional[Wires] = None,
    max_depth: int = 1,
):
    # pylint: disable=unused-argument
    return _qcut_expand_fn(tape, max_depth)


def cut_circuit_mc_expand(
    tape: QuantumTape,
    shots: Optional[int] = None,
    device_wires: Optional[Wires] = None,
    classical_processing_fn: Optional[callable] = None,
    max_depth: int = 1,
):
    # pylint: disable=unused-argument
    return _qcut_expand_fn(tape, max_depth)


cut_circuit.expand_fn = cut_circuit_expand
cut_circuit_mc.expand_fn = cut_circuit_mc_expand

I'm not sure it'll be much shorter, but it seems cleaner for both expansions to be using the same core function (reducing code duplication).

That being said, the current approach works well if we expect cut_circuit and cut_circuit_mc expansions to ever behave differently 🤔

Base automatically changed from qcut-cut-circuit-mc-transform to master April 1, 2022 19:16
Copy link
Contributor

@trbromley trbromley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @anthayes92, looks good overall but I've just requested one change to the tests.


assert spy.call_count == 2
assert spy.call_count == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should still be calling the expansion functionality twice. The issue is that we'll have to have one spy for cut_transform.expand_fn and another for qcut._qcut_expand_fn, and assert that each is called once.

Before, we had

return cut_circuit.expand_fn(tape.expand(), max_depth=max_depth - 1)

in line 1914 which meant we could get away with just one spy.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to the discussion we had in the previous PR.

@@ -3697,10 +3731,37 @@ def circuit(template_weights):

spy = mocker.spy(qcut.cut_circuit, "expand_fn")
res = qnode_cut(template_weights)
assert spy.call_count == 2
assert spy.call_count == 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here and in line 3763 of test_expansion_mc_ttn - we expand the expansion to be happening twice because we have a nested block.

Copy link
Contributor

@trbromley trbromley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @anthayes92! Approved, but worth you taking a look through at the changes too.

@anthayes92 anthayes92 merged commit 3af8ae3 into master Apr 6, 2022
@anthayes92 anthayes92 deleted the qcut-sampling-template-expansion branch April 6, 2022 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants