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

Add Operator has_matrix property #2331

Merged
merged 17 commits into from
Mar 18, 2022
Merged

Add Operator has_matrix property #2331

merged 17 commits into from
Mar 18, 2022

Conversation

albi3ro
Copy link
Contributor

@albi3ro albi3ro commented Mar 15, 2022

Currently, our simulation devices have to maintain a list of supported class names. This list can be difficult to maintain as new classes are added, and doesn't allow user defined operations to be natively executed on the simulator.

All the simulator cares about is whether or not the operation defines a matrix. If an operator defines a matrix, then the simulator can use it.

Currently, we can't determine whether or not a given operation defines a matrix without requesting it and seeing if an error is raised. Requesting a matrix is a potentially expensive call that we don't want to always perform.

With the new operator modifiers being added to PennyLane (control, adjoint, pow, prod, etc.), they define a matrix only if their nested operations define matrices. Therefore we need a method or property that can wrap this nested logic.

In the base class, we use a classproperty as often enough the has_matrix information will be available at the class level. Upcoming operator modifiers though will only be able to define this information at the instance level. So we should never rely on the information existing at the class level, but when it exists it may be convenient to use.

A subsequent PR will modify the base Device and our simulators to determine support based on the has_matrix property.

@codecov
Copy link

codecov bot commented Mar 15, 2022

Codecov Report

Merging #2331 (7de4547) into master (03799b6) will increase coverage by 0.00%.
The diff coverage is 100.00%.

@@           Coverage Diff           @@
##           master    #2331   +/-   ##
=======================================
  Coverage   99.39%   99.39%           
=======================================
  Files         229      229           
  Lines       17396    17399    +3     
=======================================
+ Hits        17290    17293    +3     
  Misses        106      106           
Impacted Files Coverage Δ
pennylane/operation.py 96.64% <100.00%> (+0.01%) ⬆️

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 03799b6...7de4547. Read the comment docs.


Note: Child classes may have this as an instance property instead of as a class property.
"""
return cls.compute_matrix != Operator.compute_matrix
Copy link
Contributor

Choose a reason for hiding this comment

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

Clever solution, I didn't know this would work?

Copy link
Contributor

@mariaschuld mariaschuld Mar 17, 2022

Choose a reason for hiding this comment

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

Quick thought: what if an op overwrites matrix. We realised at the moment none of them needs to do that, but thought of it as a potential future design, and a developer could do it without guessing the severe consequences. Shall we ignore this for now?

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 didn't know this would work till recently either.

For most operations, this default will be fine. If someone wants to overwrite matrix at some point in the future without overwriting compute_matrix, then I would trust them enough to know to overwrite has_matrix too. I don't think we should avoiding fixing an immediate problem for something that might theoretically crop up at some point way down the line.

For the operator wrappers, we will be able to do:

def has_matrix(self):
    return self.base.has_matrix

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 guess we could have:

return (cls.compute_matrix != Operator.compute_matrix) or (cls.get_matrix != Operator.get_matrix)

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice idea, the latter one!

@@ -21,6 +21,23 @@
from gate_data import I


@pytest.mark.parametrize("op_str", qml.ops.qubit.ops)
Copy link
Contributor

Choose a reason for hiding this comment

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

We moved away from the design of testing something on all ops - if a new op is added that just doesn't work for the test logic, it is a major nightmare.

I personally prefer tests that do not rely on ops being there at all. I think it is better to test exactly what we use: make a dummy op that overwrites compute_matrix and check for the dummy op.

@@ -20,6 +20,11 @@
import pennylane as qml


def test_has_matrix():
"""Test has_matrix for DisplacementEmbedding is False."""
assert not qml.DisplacementEmbedding.has_matrix
Copy link
Contributor

Choose a reason for hiding this comment

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

We were planning to define a default matrix property, using the decomposition...maybe these tests are not so important?

Relates to the above comment: do you want to test that the templates have no matrix defined, or do you want to test that your query function works? Here you are doing the former, but I'm not sure if this is something we have to test, since it is just a missing feature!

Copy link
Contributor

@mariaschuld mariaschuld left a comment

Choose a reason for hiding this comment

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

Just some comments, and I would suggest making the test more focused on the task.

@albi3ro
Copy link
Contributor Author

albi3ro commented Mar 17, 2022

@mariaschuld I've changed the tests so it now checks a generic new op in test_operations.py instead of concrete child classes.

num_wires = 1

assert not MyOp.has_matrix
assert not MyOp(wires=0).has_matrix
Copy link
Contributor

Choose a reason for hiding this comment

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

Short and sweet!

Copy link
Contributor

@mariaschuld mariaschuld left a comment

Choose a reason for hiding this comment

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

I would prefer the or cls.get_matrix.... check as well, but looks good. Nice precedent of how to implement this kind of logic!

@albi3ro albi3ro merged commit 7ed2809 into master Mar 18, 2022
@albi3ro albi3ro deleted the has-matrix branch March 18, 2022 19:47
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