-
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. |
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.