-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Make qasm output valid gate names to fix #7052 #7157
Conversation
Hi @jakelishman, thanks for the feedback! I've implemented the function |
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 looks very close to me, thanks for the effort! I had one incredibly minor point about naming (that you wouldn't really have known about), and one about another test case I thought of. I think it's very close to being done, though, so thanks for this!
def test_circuit_qasm_with_invalid_identifiers(self): | ||
"""Test that qasm() detects and corrects invalid OpenQASM gate identifiers, | ||
while not changing the instructions on the original circuit""" |
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 is a very good test, thanks! One other case that might be good to test as well: can we add two custom gates that have different invalid names, but their escaped forms would be the same? In other words, something like:
base = QuantumCircuit(1)
clash1 = QuantumCircuit(1, name="invalid??")
clash1.x(0)
base.append(clash1, [0])
clash2 = QuantumCircuit(1, name="invalid[]")
clash2.z(0)
base.append(clash2, [0])
and ensure that the de-duplication code correctly runs (so at least one of the names becomes "invalid__<id number>"
)? As written, both of these will escape their names to invalid__
, so we need to make sure the de-duplication triggers correctly.
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 for this idea!
The de-duplication code is ran correctly, but I think it's hard to check for that. The gates first go through the check that ensures they are valid identifiers, and, if they are not, a copy of the instruction is made with the valid name. Then, this copy is the one that goes through the de-duplication code, which appends the id at the end of the name.
For other tests, the id could be accessed since it is the one from the original instruction. But, in this case, the id appended is the one from the copy created by the code that ensures the name is valid. Therefore, doing the following in the test won't return the correct expected qasm.
expected_qasm = f"""OPENQASM 2.0;
include "qelib1.inc";
gate invalid__ q0 {{ x q0; }}
gate invalid___{id(clash2)} q0 {{ z q0; }}
qreg q[1];
invalid__ q[0];
invalid___{id(clash2)} q[0];\n"""
Is there a way to check that an id is appended to the end of the second instruction name without specifying that id (so, using regex)? Or what should be the approach here?
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.
We could cheat a little - we don't necessarily care how the names are de-deduplicated, just that somehow or another, they are. Given we control the input, we can limit the expected output to things we can "parse" with regular expressions: perhaps something along the lines of:
names = set()
for match in re.findall(r"gate (\S+)", base.qasm()):
gate_name = match.group(1)
self.assertTrue(VALID_QASM2_IDENTIFIER.fullmatch(gate_name))
names.add(gate_name)
self.assertEqual(len(names), ...)
In words:
- find each instance of the string "gate <gate_name> ..."
- extract the gate name from it
- check it's a valid name
- add it to a set (automatic uniqueness check)
- assert the length of the set is what we expect
That tests the behaviour we want (all names are valid, and there are no duplicates), without testing specifics of the implementation (how exactly the deduplication checker works). What I've just sketched there might not be 100% perfect, but I think the idea should work?
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've added this test. Thanks for the code! It was very helpful. I just found out doing gate_name = match.group(1)
wasn't neccesary since what is returned is already the string we are looking for because the regex pattern only has one group. Anyways, it is working 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.
Ah yeah, nice spot thanks. I messed up the distinction between re.findall
and re.finditer
- finditer
returns match objects, findall
returns the results of capture groups.
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.
Looks good to me, thanks for sticking through it!
def test_circuit_qasm_with_invalid_identifiers(self): | ||
"""Test that qasm() detects and corrects invalid OpenQASM gate identifiers, | ||
while not changing the instructions on the original circuit""" |
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.
Ah yeah, nice spot thanks. I messed up the distinction between re.findall
and re.finditer
- finditer
returns match objects, findall
returns the results of capture groups.
Oh no, wait, I'm sorry I forgot: could you add a bug fix release note ( |
Added release note, thanks for all the help @jakelishman! |
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.
Perfect, thanks!
Summary
Identifies invalid QASM gate names and converts them into valid names to fix #7052.
Details and comments
Right now, the same snippet of code is being run on the main for loop in the
qasm
function and in the_add_sub_instruction_to_existing_composite_circuits
function that is called insideqasm
for nested gate calls. Since the functionality is the same in both parts, should I create a function that does this so it can be called where needed and avoid having the same piece of code twice?Such function would look like
_ensure_name_validity(instruction: Instruction) -> Instruction
, where the same instruction is returned if the name is valid and if it is invalid, a copy of the instruction with the modified valid name will be returned. If its best to create such function, should I add this to the end of the file with the other functions that start with_
?