-
Notifications
You must be signed in to change notification settings - Fork 71
Fix #853: improve formatter for pretty-printing musical score diagrams #1658
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
base: main
Are you sure you want to change the base?
Conversation
@@ -191,6 +191,7 @@ def build_composite_bloq(self, bb: 'BloqBuilder', **soqs: 'SoquetT') -> Dict[str | |||
if self.cost_dtype.signed: | |||
out[0] = bb.add(ZPowGate(exponent=1, eps=eps), q=out[0]) | |||
offset = 1 + self.cost_dtype.num_frac - self.num_frac_rotations | |||
offset = offset if isinstance(offset, int) else 1 |
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.
what is the reason for this change? (add a comment?)
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 noted this in the issue as a concern/question.
The instructions in the issue do not lead to completion. There is an indexing error in one of the iterations in the loop below this line I added.
qvr_zpow = QvrZPow(Register('x', QFxp(12, 6, False)), gamma = sympy.Symbol('Y'))
show_bloq(qvr_zpow, 'dtype')
show_bloq(qvr_zpow.decompose_bloq(), 'musical_score')
Perhaps I'm missing a step or something. Else, it is a pre-existing bug that might be related to the small angle rotations changes in 38db1af
In the next commit, this line will move to inside the loop to minimise its involvement to only when strictly necessary.
for i in range(num_rotations):
power_of_two = i - self.num_frac_rotations
exp = (2**power_of_two) * self.gamma * 2
offset = offset if isinstance(offset, int) else 1 # offset -> 1 if not int to avoid indexing errors #HERE
out[-(i + offset)] = bb.add(ZPowGate(exponent=exp, eps=eps), q=out[-(i + offset)])
return {self.cost_reg.name: bb.join(out, self.cost_dtype)}
However, this is only to ensure things proceed as needed for testing of the feature in this issue.
If the instructions to produce the foundational diagram were incomplete, please let me know.
If it is a bug, it should be checked separately.
qualtran/drawing/_show_funcs.py
Outdated
@@ -142,3 +145,81 @@ def show_bloq_via_qpic(bloq: 'Bloq', width: int = 1000, height: int = 400): | |||
|
|||
IPython.display.display(Image(output_file_path, width=width, height=height)) | |||
os.remove(output_file_path) | |||
|
|||
|
|||
def pretty_format_msd(msd: MusicalScoreData) -> MusicalScoreData: |
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.
this function should live in musical_score.py
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.
Moving it. I can also use a smaller function for each soq rather than the entire msd.
Will show in next commit.
Will also add a test in the corresponding file (now possible since its a soq-level function).
qualtran/drawing/_show_funcs.py
Outdated
|
||
def pretty_format_msd(msd: MusicalScoreData) -> MusicalScoreData: | ||
""" | ||
Beautifies MSD to enable pretty diagrams |
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.
explain what transformations are done
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.
Will do. Shows in next commit.
qualtran/drawing/_show_funcs.py
Outdated
lbl_raw = soq_item.symb.text | ||
lbl_no_symbols, symbol = symbols_to_identity(lbl_raw) | ||
gate, base, exponent = sum([p.split("**", 1) for p in lbl_no_symbols.split("^")], []) | ||
|
||
if len(base.split("*", 1)) > 1: | ||
mult_str, base = base.rsplit("*", 1) | ||
mult = sympy.sympify(mult_str, evaluate=True) | ||
|
||
exponent = sympy.sympify(exponent, locals=simpify_locals, evaluate=True) | ||
expression = str(base) + "**" + str(exponent) | ||
expression = sympy.sympify(expression, locals=simpify_locals, evaluate=True) | ||
new_lbl = str(gate) + "^" + symbol + "*" + str(expression * mult) |
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'm not sure what this code aims to do, but it seems rather brittle. Why are we replacing parts of the label with the character "1"
?
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.
Right, yes! You are completely right.
So, any errors fallback to the original label, which ensures completion, but I can make it more robust in the next commit.
More importantly, the mathematical concern is undeniably valid.
It's clear I took the diagram examples in the issue too literally, perhaps assuming there was some quantum magic happening somewhere that escaped me.
Thinking about it as a standard symbolic equation, there seems to be a need to define a preference:
- semi-pretty labels: some simplification is possible if Abs(Y) is not evaluated with some sort of substitution (which would affect other Y values), but the pretty version won't be entirely pretty. (better than nothing I guess)
- arbitrary replacement: pi, 2*pi, some random value? (no likey, not symbolic anymore)
- user-input placeholder: user chooses what value to use for evaluation (same)
- a panel of diagrams: several rotation angles rendered as a panel of diagrams rather than a single panel diagram (quite a deviation from original concept so I'm hoping there is another approach I'm not considering but, somewhat applicable).
I'll work a little on the next commit but it would be cool if you could tell me your views on the matter and potential alternatives not considered, to avoid the need for many additional commits.
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.
Actually, after running a few tests if seems the combination of factors is such that only very very very small angles would lead to a difference, in which case, might as well use pi to evaluate the Abs value in the expression. Will explain thoroughly in comments.
@mpharrigan |
@jbolns Run Also, if you don't have it set up locally, I suggest using wsl and running all the CIs locally so that when the maintainers run the CI, you'd know it's gonna pass and move directly to merge or further notes. |
Done, @ACE07-Sev. |
For reference, I'm copying here the image from a comment by the original author in issue #853 that shows a screenshot of the output produced by the code in this PR: |
@jbolns With respect to the output produced by your code currently (c.f. previous comment above), let's step back a bit and review some conventions of these "musical score diagrams":
Now, with this in mind, comparing the original description in issue #853 where @tanujkhattar showed a screenshot illustrating the format of the diagrams, a discrepancy becomes apparent. The original always has the bloq/gate/operation name in the box, and parameters above the box: By contrast, in your image, the entire text is inside the box: So, this is the first thing I suggest be addressed in the PR: move the parameters or arguments (in this case, rotation angles) out and above the boxes. |
I'm very happy for this feedback and would like to investigate a solution for it. Having said that, I do believe it would be best to merge this PR first and then address this formatting matter as part of a new broader issue revisiting the entire MSD workflow. The reasoning is as follows. Currently, without anything in this PR (except the one-line fix in If you didn't change the placement of labels intentionally, then it means the change went unnoticed. That's already the second such situation, the first being the bug that made it necessary for me to include the one-line fix in Things like this tend to go unnoticed when they are collateral damage from changes to other (more important) features. As such, I am in a professional obligation to consider that if I change this back on a rush, to meet the deadline of the hackathon, I might undo changes introduced for reasons more important than MSDs. To do this appropriately, thus, I would need to take a deep dive into past commits to learn what happened and how can it be fixed without additional collateral damage. This takes time and goes far beyond adding a simple pretty formatter. Ergo, I suggest merging the pretty formatter in this PR and then open a broader issue for "revising the MSD workflow" with a description along the lines of "PR #1658 introduced a pretty formatter for MSDs and found a number of inconsistencies with the MSD workflow that appear to result from pre-existing changes to the codebase. It would be ideal to review the MSD workflow to ensure it is working efficiently and gives users the option to print full or pretty results using the changes introduce in 1658". This is really only a suggestion made from my very limited point of view. It is, of course, your repository, so I will respect your choice. Either way, I can only work more on this starting end of week. |
I have added a new commit. As seen in the image below, it recovers the content (though not the formatting) of labels as illustrated on the original issue. If both the content and formatting can be recovered, prettification should be waaaaaaay easier. To begin, since the expression is already given fairly simplified, I do not need to worry about potential variation in mathematical patterns. The whole sympify situationship might not even be necessary. Why? / What? / Where? / When? A.
The fix in this PR's last commit (i.e., the one I just pushed) keeps everything in the newest version except the misbehaving lines. To get a sense of whether this combined version could be problematic, before changing the lines in this PR, I created a test local branch to rebase the code all the way from 38db1af. There was only one conflict that required solving:
B.
It is a significant commit, so I will explore it at a different point in time. |
The changes in this PR enable pretty print of musical score diagrams.
The changes in
qualtran\drawing\_show_funcs.py
aim to be enable pretty formatting in a way that is independent from internal logic (to allow for changes) but flexible (to easily adapt to any changes):If the internal logic changes and labels change (I estimate minimally to moderately), the approach can be adapted by modifying the foundational RegEx capture of symbols and/or the locals for simpify.
&
PR also include a small change to
qualtran\bloqs\rotations\quantum_variable_rotation.py
. Perhaps I missed something when I set things up since I am submitting this PR as part of unitaryHack and there is limited time to get familiar with the codebase. That said, theoffset
was causing errors.Closes #853
Maybe.
Ps. I tend to use more space and comments, but I tried my best to stick to the style in the target files. Happy to expand.