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

[WIP] Add mitigation support using mitiq backend #1783

Closed
wants to merge 11 commits into from

Conversation

trbromley
Copy link
Contributor

@trbromley trbromley commented Oct 21, 2021

Context:

The mitiq library recently merged-in support for input PennyLane tapes. This PR explores how this functionality can be wrapped to support a standard PennyLane workflow.

Description of the Change:

Adds a new mitigate module (+ making visible in documentation and an incomplete set of tests). The module contains:

  • add_noise_to_tape() and add_noise_to_device() transforms that allow for quick prototyping of noisy circuits without running on hardware (this could live in the transforms module)
  • mitiq_interface() function for wrapping standard functionality from the mitiq library (e.g. execute_with_zne), allowing these functions to accept general PL tapes as input circuits and PL devices as executors.
  • mitigate_device() device transform that adds mitigation automatically to the device using mitiq as a backend.

Example UI:

Here are some examples of how a user may interact with the mitigate module.

Using mitigate_device

from mitiq import zne
from mitiq.zne.scaling import fold_global

dev = qml.device("default.mixed", wires=2)  # Load device
dev = qml.mitigate.add_noise_to_device(dev, qml.AmplitudeDamping, 0.2, position="all")  # Make device noisy
dev = qml.mitigate.mitigate_device(dev, zne.execute_with_zne, {"scale_noise": fold_global})  # Mitigate device

@qml.qnode(dev)
def f(w, x, y, z):
   qml.RX(w, wires=0)
    qml.RY(x, wires=1)
    qml.CNOT(wires=[0, 1])
    qml.RZ(y, wires=0)
    qml.RX(z, wires=1)
    return qml.expval(qml.PauliZ(0))

>>> f(0.9, 0.4, 0.5, 0.6)
tensor(0.71966579, requires_grad=True)  # Result is mitigated

Using mitiq_interface

from mitiq import zne
from mitiq.zne.scaling import fold_global

dev = qml.device("default.mixed", wires=2)
dev = qml.mitigate.add_noise_to_device(dev, qml.AmplitudeDamping, 0.2, position="all")

with qml.tape.QuantumTape() as tape:
    qml.RX(0.9, wires=0)
    qml.RY(0.4, wires=1)
    qml.CNOT(wires=[0, 1])
    qml.RZ(0.5, wires=0)
    qml.RX(0.6, wires=1)
    qml.expval(qml.PauliZ(0))

>>> qml.mitigate.mitiq_interface(zne.execute_with_zne)(tape, dev, scale_noise=fold_global)
0.7196657937904828

Benefits:

Mitigation is available within PennyLane, including for gradients.

Possible Drawbacks:

  • The current approach does not support differentiability with respect to the hyperparameters of the mitigation procedure
  • The mitigate_device() transform uses the mitiq execute_with_* function as a black box. We allow execute_with_* to handle the transformation of the circuit into multiple circuits (e.g. gate folding) and the composition of the execution results into a mitigated value (e.g. extrapolation). This allows us to be agnostic toward the mitigation method.

Related PR:

supersedes #1183

@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 Oct 21, 2021

Codecov Report

Merging #1783 (6f67cb6) into master (f7895fa) will decrease coverage by 0.33%.
The diff coverage is 43.61%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1783      +/-   ##
==========================================
- Coverage   98.90%   98.56%   -0.34%     
==========================================
  Files         206      207       +1     
  Lines       15403    15497      +94     
==========================================
+ Hits        15234    15275      +41     
- Misses        169      222      +53     
Impacted Files Coverage Δ
pennylane/mitigate.py 43.01% <43.01%> (ø)
pennylane/__init__.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 f7895fa...6f67cb6. Read the comment docs.

def new_executor(updated_tape):
with QuantumTape() as updated_tape_with_measurements:
for op in updated_tape.operations:
op.queue()
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
op.queue()
qml.apply(op)

this will be safer than calling queue :)

def new_executor(updated_tape):
with QuantumTape() as updated_tape_with_measurements:
for op in updated_tape.operations:
op.queue()
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
op.queue()
qml.apply(op)

this will be safer than calling queue :)

return new_tape


def add_noise_to_tape(tape, noisy_op: Operation, noisy_op_args, position: str = "all"):
Copy link
Member

Choose a reason for hiding this comment

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

@trbromley you could also

  • Decorate this with @qml.single_tape_transform, to help remove some of the boiler plate (it allows you to remove the with QuantumTape() as noisy_tape: context manager)

  • Also provide a @qml.qfunc_transform version of this function, that allows it to work on qfuncs

add_noise_to_qfunc = qml.qfunc_transform(add_noise_to_tape)

@add_noise_to_qfunc(qml.AmplitudeDamping, 0.2, position="all")
def circuit():
    qml.RX(0.9, wires=0)
    qml.RY(0.4, wires=1)
    qml.CNOT(wires=[0, 1])
    qml.RZ(0.5, wires=0)
    qml.RX(0.6, wires=1)
    return qml.expval(qml.PauliZ(0))

Although I don't know if this is something you would want in your workflow or not :)

Comment on lines +265 to +267
def execute(circuit, **kwargs):
noisy_circuit = add_noise_to_tape(circuit, noisy_op, noisy_op_args, position)
return original_execute(noisy_circuit, **kwargs)
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious if you got this to work via the expand_fn approach?

    dev = deepcopy(dev)
    original_expand_fn = dev.expand_fn

    def expand_fn(self, circuit, **kwargs):
        circuit = original_expand_fn(circuit, **kwargs)
        return add_noise_to_tape(circuit, noisy_op, noisy_op_args, position)

    dev.expand_fn = types.MethodType(expand_fn, dev)
    return dev

>>> tape.execute(dev)
[0.97578304]
"""
dev = deepcopy(dev)
Copy link
Member

Choose a reason for hiding this comment

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

I worry that not all devices might be deepcopyable? Might not be an issue though

Comment on lines +265 to +267
def execute(circuit, **kwargs):
noisy_circuit = add_noise_to_tape(circuit, noisy_op, noisy_op_args, position)
return original_execute(noisy_circuit, **kwargs)
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious if you got this to work via the expand_fn approach?

    dev = deepcopy(dev)
    original_expand_fn = dev.expand_fn

    def expand_fn(self, circuit, **kwargs):
        circuit = original_expand_fn(circuit, **kwargs)
        return add_noise_to_tape(circuit, noisy_op, noisy_op_args, position)

    dev.expand_fn = types.MethodType(expand_fn, dev)
    return dev

@trbromley
Copy link
Contributor Author

Closing because superseded by #1813

@trbromley trbromley closed this Oct 27, 2021
@trbromley trbromley deleted the mitigation_tape_transform branch October 27, 2021 15:55
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.

2 participants