-
Notifications
You must be signed in to change notification settings - Fork 369
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 SymbolicOperator and tests #194
Conversation
So there's good news and bad news. 👍 The good news is that everyone that needs to sign a CLA (the pull request submitter and all commit authors) have done so. Everything is all good there. 😕 The bad news is that it appears that one or more commits were authored by someone other than the pull request submitter. We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that here in the pull request. Note to project maintainer: This is a terminal state, meaning the |
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.
Thanks Kevin, this PR is looking great. I am surprised though that you weren't able to checkout @bgimby's PR. If you clone his fork, which is public at (https://github.com/bgimby/OpenFermion) then you should be able to checkout his feature branch. But in any event, I think it is fine to merge this from your fork. But do try to work off of @bgimby's fork for the next PR so that he gets some credit in the "contributors" section for the lines of code contributed.
Aside from a comment about Latin abbreviations, I think your PR is basically good to go. I have a couple questions though because I want to completely understand the plan before moving forward.
Note that the performance of FermionOperator and QubitOperator is very important to us. It might be a good idea to check performance by looking at the "performance_benchmarks" in the examples folder to make sure we aren't slowing down these classes. One important question: did you alter any of the magic methods like add, mul, etc. in any way that could possibly effect performance?
If not, I think we are basically ready to merge.
SymbolicOperators of the same type can be added or multiplied together. | ||
|
||
Attributes: | ||
actions (tuple): A tuple of objects representing the possible actions. |
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.
I wonder if it would be better if everything other than the terms attribute were a private attribute that is accessed with getters/setters. I am not necessarily of that belief, but it is worth thinking about. @jarrodmcc do you have any thoughts?
# Add the term to the dictionary | ||
self.terms[term] = coefficient | ||
|
||
def _long_string_init(self, term, coefficient): |
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.
Is there a reason why this needs to be implemented differently for FermionOperator and QubitOperator? Otherwise, I feel we should implement the method now.
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.
No, there is no reason. It's just that @max-radin said he would do it at #177 so I figured I'd leave it to him. Perhaps we should post there asking if he's still willing to do it? I figured we can leave it unimplemented here and then post about it there after merging. In any case I'd be happy to write this.
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 let's ask him about that.
def _parse_sequence(self, term): | ||
"""Parse a term given as a sequence type (i.e., list, tuple, etc.). | ||
|
||
i.e. For QubitOperator: |
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.
I think you mean "e.g." not "i.e."
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.
Ok I will change these.
def _parse_string(self, term): | ||
"""Parse a term given as a string. | ||
|
||
i.e. For FermionOperator: |
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.
You mean "e.g." not "i.e."
def __repr__(self): | ||
return str(self) | ||
|
||
def __imul__(self, multiplier): |
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.
So is the idea that for QubitOperator we will overwrite this class? Because in that case there is a more optimized way to multiply which is based on knowledge of the fact that the QubitOperator terms are sorted by tensor factor. I think that is fine, I am just trying to understand.
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.
Yes, the idea is that QubitOperator will overwrite this method using its existing implementation. This is just the most general multiplication method that doesn't take into account any additional structure in the space of operators.
Actually, I did work off of @bgimby's fork. I just couldn't add commits to the PR he created because that required me to push directly to his branch, which I don't have write access to. Creating a PR gives write access to maintainers of the main repository. The first two commits of this PR belong to him so I think he will get credit on the Contributor's page. @bgimby was the one who ported most of the magic methods. It looks to me that they are unmodified; do you have anything else to say about that @bgimby? I made sure that |
I did not modify any of the magic methods. It's possible that there is extra overhead in calling a base class's method from a subclass, though I'm not sure. If there are any performance losses, or indeed any performance issues I'll be happy to work on them when I have the time- I like working on optimization, though I haven't had a chance to do much in python. |
In that case, I think we're pretty much good to go. Kevin, let me know when we're ready. Also, @kevinsung did you have a chance to figure out why the docs were failing from your last PR? If you have any idea it would be good to also fix that in this PR. |
# Add the term to the dictionary | ||
self.terms[term] = coefficient | ||
|
||
def _long_string_init(self, term, coefficient): |
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 let's ask him about that.
Somehow the docs are unbroken. I think it was some glitch in read-the-docs. |
* Added SymbolicOperator Class * PR fixes * documentation and init * add test file * add default implementation for imul * add action attributes * write str and parse_sequence * steal tests from FermionOperator and QubitOperator * remove uses of SymbolicOperatorError * edit docs * lint * remove some whitespace * make _parse_string self-contained * add duplicate terms multiplication test * remove extraneous imports * change iadd to use EQ_TOLERANCE * correct Latin abbreviations
I couldn't add commits to #191 because I don't have write access to the main repo, so I'm replacing it with this PR. Some notes on my implementation:
different_indices_commute
for is to see if we can reorder the factors in terms so that the indices are in ascending order. To get a functioning subclass it's enough to set these four attributes; I removed the uses of abstract base class methods (from the moduleabc
) which were introduced in Added SymbolicOperator Class #191.__str__
preserves the current string representations for FermionOperators, but would slightly alter those of QubitOperators. Namely, operators would be surrounded in square brackets, and the identity term would be represented as[]
instead ofI
. For instance, we would haveinstead of
Of course, we can override this behavior but using the unified implementation will make it possible for #177 to be implemented only in SymbolicOperator.
_long_string_init
which I left unimplemented._fermion_operator_test.py
and_qubit_operator_test.py
. In the test file, the tests forDummyOperator1
were from_fermion_operator_test.py
and the tests forDummyOperator2
were from_qubit_operator_test.py
(modified to remove the dependence onpytest
).SymbolicOperatorError
withValueError
because I couldn't tell when one should be used over the other.__imul__
.