-
Notifications
You must be signed in to change notification settings - Fork 575
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
Support returning the metric tensor of ExpvalCost in tape mode #911
Changes from 7 commits
c64c803
b729f9f
9d505e0
00fb33c
6a16deb
be11c6d
ff9394a
0a2264c
0b77535
c8d4ec4
fd97203
b4fd9ed
d539c4f
e2fccd4
cea36c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -470,10 +470,29 @@ def __init__( | |
"""QNodeCollection: The QNodes to be evaluated. Each QNode corresponds to the expectation | ||
value of each observable term after applying the circuit ansatz.""" | ||
|
||
wires = device.wires.tolist() | ||
|
||
tape_mode = qml.tape_mode_active() | ||
if tape_mode: | ||
try: | ||
qml.disable_tape() | ||
@qml.qnode(device, interface=interface, diff_method=diff_method, **kwargs) | ||
def qnode_for_metric_tensor_in_tape_mode(*qnode_args, _wires=wires, **qnode_kwargs): | ||
"""The metric tensor cannot currently be calculated in tape-mode QNodes. As a | ||
short-term fix for VQECost, we create a non-tape mode QNode just for | ||
calculation of the metric tensor. In doing so, we reintroduce the same | ||
restrictions of the old QNode but allow users to access new functionality | ||
such as measurement grouping and batch execution of the gradient.""" | ||
ansatz(*qnode_args, wires=_wires, **qnode_kwargs) | ||
return qml.expval(qml.PauliZ(0)) | ||
self._qnode_for_metric_tensor_in_tape_mode = qnode_for_metric_tensor_in_tape_mode | ||
finally: | ||
qml.enable_tape() | ||
|
||
self._optimize = optimize | ||
|
||
if self._optimize: | ||
if not qml.tape_mode_active(): | ||
if not tape_mode: | ||
raise ValueError( | ||
"Observable optimization is only supported in tape mode. Tape " | ||
"mode can be enabled with the command:\n" | ||
|
@@ -482,8 +501,6 @@ def __init__( | |
|
||
obs_groupings, coeffs_groupings = qml.grouping.group_observables(observables, coeffs) | ||
|
||
wires = device.wires.tolist() | ||
|
||
@qml.qnode(device, interface=interface, diff_method=diff_method, **kwargs) | ||
def circuit(*qnode_args, obs, **qnode_kwargs): | ||
"""Converting ansatz into a full circuit including measurements""" | ||
|
@@ -523,12 +540,11 @@ def metric_tensor(self, args, kwargs=None, diag_approx=False, only_construct=Fal | |
Returns: | ||
array[float]: metric tensor | ||
""" | ||
if self._optimize: | ||
raise ValueError( | ||
"Evaluation of the metric tensor is not supported when using " | ||
"optimized observables. Set the argument optimize=False to obtain " | ||
"the metric tensor." | ||
if qml.tape_mode_active(): | ||
return self._qnode_for_metric_tensor_in_tape_mode.metric_tensor( | ||
args=args, kwargs=kwargs, diag_approx=diag_approx, only_construct=only_construct | ||
) | ||
|
||
# all the qnodes share the same ansatz so we select the first | ||
return self.qnodes.qnodes[0].metric_tensor( | ||
args=args, kwargs=kwargs, diag_approx=diag_approx, only_construct=only_construct | ||
|
@@ -546,6 +562,6 @@ class VQECost(ExpvalCost): | |
def __init__(self, *args, **kwargs): | ||
warnings.warn( | ||
"Use of VQECost is deprecated and should be replaced with ExpvalCost", | ||
DeprecationWarning, | ||
DeprecationWarning, 2 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I noticed that without this, warnings to not appear to users! |
||
) | ||
super().__init__(*args, **kwargs) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1500,3 +1500,29 @@ def circuit(a, b, c, d, *args): | |
# the user will evaluate the QNode with. | ||
node.set_trainable_args({0, 1, 6}) | ||
assert node.get_trainable_args() == {0, 1, 6} | ||
|
||
|
||
def test_old_qnode_in_tape_mode(): | ||
"""Test that the old QNode can still be evaluated when running in tape mode""" | ||
|
||
# tape mode should not be active so that we can use the old QNode | ||
assert not qml.tape_mode_active() | ||
|
||
try: | ||
dev = qml.device("default.qubit", wires=2) | ||
|
||
@qml.qnode(dev) | ||
def f(x): | ||
qml.RX(x, wires=0) | ||
qml.RY(0.4, wires=1) | ||
qml.CNOT(wires=[0, 1]) | ||
return qml.expval(qml.PauliZ(0)) | ||
|
||
qml.enable_tape() | ||
f(0.4) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be worth to check the output here. Just to make sure it's not doing something weird (like returning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great, I just added a check against the hardcoded expected result: cea36c5 |
||
|
||
# check that tape mode is turned on again after evaluating the old QNode | ||
assert qml.tape_mode_active() | ||
|
||
finally: # always make sure we turn off tape mode to prevent disrupting the other tests | ||
qml.disable_tape() | ||
Comment on lines
+1530
to
+1531
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like we need a context manager
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah definitely. While
try
-finally
is, to all intents and purposes, a low-effort context manager, it would be nice.Note that
qml.enable_tape()
currently doesn't return anything, so it would be very easy to turn it into a context manager in addition to its current role. For example,This way, you could keep using it as before,
or you could use it as a context manager
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's awesome! I'll make a ticket and link to this comment, thanks.