Conversation
One of my inspirations for generating a single string ID rather than a structure was because I intended for it to be static and opaque, i.e. it was intended to only be used for equality comparison. Do we need greater functionality than this? Not that a structure is worse, in fact it might be better in terms of performance, but I worry that this will encourage more manipulation of IDs (similar to what we see with adjoint/control modifiers in the frontend right now). My goal would be to generate new IDs from operator data rather than manipulate ID data, though maybe at this point I'm holding on to an idea that will only get in our way... |
I agree that the ID should be opaque (at least for the code, inspectability aside), however that is already not the case in two instances: generating adjoint/control versions of decomposition reaches in and manipulates strings, and generating the shortened name to compare against the gate set. I would support moving towards never touching the ID once it's generated. In this PR, I don't really change that fact. The ID is generated by going through a structured attribute first, but then it is serialized to string. There is still the parsing of the string for the two use-cases I mention above. Perhaps we can fix those first. |
|
@dime10 Sounds like we're on the same page, and I agree that sending everything to MLIR attributes then serializing for consistency is ideal. Let's go ahead with this (I'll review shortly) and I can try to address the string manipulation in a separate PR :) |
I don't really like how many changes there are in this PR (although a lot of them are tests), so I am experimenting with an alternative implementation. Not sure I've landed on something I really like yet 🤔 |
This PR makes a narrow update to the graph op ID generation mechanism to use a single source of truth for static data portion only. The general approach consists of generating MLIR objects (attributes) first via the Python bindings, and then use the builtin printer to serialize those fields to string for the ID. This change does not constitute a single source of truth for the entire ID (unlike #3184), as other fields (e.g. parameter printing), and the structure itself, still use duplicated logic across Python & C++ that must be matched precisely. However, the entire could potentially be migrated in stages with this representing the first step. Additionally, all generation/formatting functions are refactored to be centralized in one place. --------- Co-authored-by: River McCubbin <river.mccubbin@xanadu.ai>
Context:
Graph operation identifiers were independently assembled as delimiter-based strings in the Python frontend and C++ compiler. This made the encoding sensitive to formatting differences, some of which are identified below:

Description of the Change:
This PR replaces the existing GraphOpID encodings across the frontend and compiler with the canonical MLIR representation of a typed dictionary attribute. It does this by converting Python values to MLIR attributes first, assembling the full GraphOpID attribute structure (the "struct"), and then converting to string via the builtin MLIR attribute printers. The conversion to string could be eliminated entirely, but to limit the scope of the PR I'm keeping the string representation in all the users of the GraphOpID.
The struct schema is roughly based on the following:
op,wiresandparametertypes instead of dictionaries to keep the ID shorter,traits(this is mainly done to highlight the op name more, otherwise the adjoint field would be printed first by MLIR),All frontend producers use a shared
build_graph_op_keyhelper. TheDecomposableGatedefault implementation constructs the equivalent attribute in C++, but will still produce a string as a result.Benefits:
Possible Drawbacks:
To limit the scope of the PR, I didn't change any consumer code of the GraphOpID, so it still expects strings. As a result, we still have a conversion of the structured dictionary representation to string, and on the other side a parsing step currently used for two reasons: generating modified IDs (e.g. adding an adjoint), and obtaining a simplified name for gate set matching. Ideally, the ID should be fully opaque, and once generated not touched except to test equality. Hopefully something we can further improve in the future.