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

Implement qml.breakpoint() and initial integration with Pdb #5600

Merged
merged 21 commits into from
Jun 6, 2024

Conversation

Jaybsoni
Copy link
Contributor

@Jaybsoni Jaybsoni commented Apr 30, 2024

Context:
Part of the effort to add more tools for algorithmic debugging of quantum circuits with PennyLane. In this PR we introduce the qml.breakpoint() function which allows users to insert breakpoints into their quantum workflow and enter a debugging context (via Pdb) to step through their quantum functions.

Description of the Change:

  • Added a PLDB class which inherits most of its functionality from Pdb.
  • Added functionality to pass active device information into the debugger during qnode execution to validate the compatibility between the device and the debugger.

image

@Jaybsoni Jaybsoni added the WIP 🚧 Work-in-progress label Apr 30, 2024
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.

@Jaybsoni
Copy link
Contributor Author

[sc-62243]

@Jaybsoni
Copy link
Contributor Author

Open Questions:

  • Do we want to take any specialized actions when users call step down or step up? Restrict it? Raise a warning? (Currently it is allowed and leads the user into complex pennylane internals)
  • How should we test the breakpoint functionality without triggering the interactive debugger in the test suite? Are there any industry standards here?
  • I have currently added validation checks for incompatible devices (anything other than lightning.qubit and default.qubit) as well is if the breakpoint is called outside of a qnode execution. Any thoughts on this?

@Jaybsoni Jaybsoni changed the title [WIP] Implement qml.breakpoint() and initial integration with Pdb Implement qml.breakpoint() and initial integration with Pdb Apr 30, 2024
@Jaybsoni Jaybsoni added review-ready 👌 PRs which are ready for review by someone from the core team. and removed WIP 🚧 Work-in-progress labels Apr 30, 2024
pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Show resolved Hide resolved
pennylane/workflow/qnode.py Outdated Show resolved Hide resolved
Copy link

codecov bot commented Apr 30, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.67%. Comparing base (fbc2a39) to head (26f28f9).
Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #5600      +/-   ##
==========================================
- Coverage   99.68%   99.67%   -0.01%     
==========================================
  Files         416      416              
  Lines       39105    38432     -673     
==========================================
- Hits        38981    38307     -674     
- Misses        124      125       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

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 @Jaybsoni!

pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Show resolved Hide resolved
@Jaybsoni Jaybsoni requested review from mlxd and trbromley May 10, 2024 21:02
@Jaybsoni Jaybsoni requested a review from Mandrenkov May 23, 2024 20:15
Copy link
Contributor

@DSGuala DSGuala left a comment

Choose a reason for hiding this comment

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

Looks good to me!

  • qml.breakpoint() pauses execution ✔️
  • Tested the commands while debugging (list, next, continue, quit) and they all worked fine. ✔️ One note here: hitting next at the return statement of the circuit puts us into PL internals, but I think that's fine.
  • Can access internal and external variables from the debugging context ✔️
  • Can queue additional operations ✔️

Pending for next PRs:

  • qml.debugging.state()
  • qml.debugging.expval()
  • qml.debugging.tape()

I think we can keep this open and merge other PRs into this branch. Having the docs will especially help with PR reviews.

pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/workflow/qnode.py Outdated Show resolved Hide resolved
Copy link
Contributor

@Mandrenkov Mandrenkov left a comment

Choose a reason for hiding this comment

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

Neat stuff, @Jaybsoni! I left a few minor comments and suggestions.

pennylane/debugging.py Show resolved Hide resolved
pennylane/debugging.py Show resolved Hide resolved
pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Show resolved Hide resolved
pennylane/workflow/qnode.py Outdated Show resolved Hide resolved
tests/test_debugging.py Outdated Show resolved Hide resolved
tests/test_debugging.py Show resolved Hide resolved
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.

No blockers to merging from me! Thanks @Jaybsoni!

pennylane/debugging.py Show resolved Hide resolved
@Jaybsoni Jaybsoni changed the base branch from master to debugging_feature May 30, 2024 14:58
@Jaybsoni Jaybsoni requested review from soranjh and DSGuala May 30, 2024 19:22
@Jaybsoni Jaybsoni requested a review from Mandrenkov May 30, 2024 20:41
Copy link
Contributor

@soranjh soranjh left a comment

Choose a reason for hiding this comment

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

Thanks @Jaybsoni, looks good to me.

Merge branch 'debugging_feature' into algo_debug_breakpoint
pennylane/debugging.py Outdated Show resolved Hide resolved
def __init__(self, *args, **kwargs):
"""Initialize the debugger, and set custom prompt string."""
super().__init__(*args, **kwargs)
self.prompt = "[pldb]: "
Copy link
Contributor

Choose a reason for hiding this comment

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

Will this be mutable, or could it be defined via property?

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there value in making the prompt mutable? I think it's OK for this to be hidden state.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It shouldn't be mutable, I can re-define it as a property. It should be internal anyways

Copy link
Contributor Author

@Jaybsoni Jaybsoni Jun 5, 2024

Choose a reason for hiding this comment

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

Actually, Pdb complains if we implement it as a property. Leaving it as is.

class PLDB(pdb.Pdb):
"""Custom debugging class integrated with Pdb."""

__active_dev = None
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
__active_dev = None
__active_dev : Optional[qml.devices.Device] = None

Trying to get better about type-hints throughout pennylane. Helps specify things a little bit more.

Copy link
Contributor

@Mandrenkov Mandrenkov Jun 3, 2024

Choose a reason for hiding this comment

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

Not sure what the PennyLane coding standards say, but in Python 3.9+ you can use:

Suggested change
__active_dev = None
__active_dev: qml.devices.Device | None = None

Copy link
Contributor

Choose a reason for hiding this comment

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

We'll be supporting 3.9 till after the next release.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yep. I mean that if we don't support Python 3.8 or lower, we can use the | syntax.

Copy link
Contributor Author

@Jaybsoni Jaybsoni Jun 5, 2024

Choose a reason for hiding this comment

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

I tried adding the type hint, but its causing circular import issues.

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 be able to get around that issue by using

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pennylane.devices import Device

but I'm sure we can leave that as a future enhancement.

Comment on lines +936 to +938
# Before constructing the tape, we pass the device to the
# debugger to ensure they are compatible if there are any
# breakpoints in the circuit
Copy link
Contributor

Choose a reason for hiding this comment

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

So is this just for checking compatibility? If so, do we need to use a context with an enter-exit just for checking validity?

Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW I think having a "is this device compatible with breakpoints" function makes sense although I'm not sure it would be too useful here (unless we know ahead of time that the current circuit has a breakpoint).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think that's the key, we don't need to do validation checks if there are no breakpoints in the circuit. Furthermore, we use the device to execute measurements (see the following PR), so we do need the context.

pennylane/debugging.py Outdated Show resolved Hide resolved
Copy link
Contributor

@Mandrenkov Mandrenkov left a comment

Choose a reason for hiding this comment

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

Thanks for the updates, @Jaybsoni! 🚀

I especially think the skip change adds good value.

pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Outdated Show resolved Hide resolved
def __init__(self, *args, **kwargs):
"""Initialize the debugger, and set custom prompt string."""
super().__init__(*args, **kwargs)
self.prompt = "[pldb]: "
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there value in making the prompt mutable? I think it's OK for this to be hidden state.

pennylane/debugging.py Outdated Show resolved Hide resolved
pennylane/debugging.py Show resolved Hide resolved
tests/test_debugging.py Show resolved Hide resolved
tests/test_debugging.py Outdated Show resolved Hide resolved
tests/test_debugging.py Outdated Show resolved Hide resolved
tests/test_debugging.py Outdated Show resolved Hide resolved
tests/test_debugging.py Show resolved Hide resolved
Jaybsoni and others added 4 commits June 5, 2024 12:03
Co-authored-by: Mikhail Andrenkov <[email protected]>
Merge branch 'debugging_feature' into algo_debug_breakpoint
Copy link
Contributor

@Mandrenkov Mandrenkov left a comment

Choose a reason for hiding this comment

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

Thanks for addressing the feedback, @Jaybsoni! 🚀

class PLDB(pdb.Pdb):
"""Custom debugging class integrated with Pdb."""

__active_dev = None
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 be able to get around that issue by using

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pennylane.devices import Device

but I'm sure we can leave that as a future enhancement.

@Jaybsoni Jaybsoni merged commit 1a652a7 into debugging_feature Jun 6, 2024
37 checks passed
@Jaybsoni Jaybsoni deleted the algo_debug_breakpoint branch June 6, 2024 02:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
review-ready 👌 PRs which are ready for review by someone from the core team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants