-
Notifications
You must be signed in to change notification settings - Fork 314
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
Support extern
gate declarations
#507
Comments
@hodgestar pointed out that the relation of such an |
implementations (of parsers, compilers ?) should behave as if "stdgates.qasm" were present, and is if it contained a precise collection of declarations. So the present issue is not relevant for However, some backend might provide other gates, but for some reason (there are several possible) does not want to expose their definitions in an API. In this case, we need an organized way for the compiler to allow valid use of In this case, gate myspecialgate(r, s, t) q0, q1 {} is a fragile hack that confuses two concepts.
|
An |
My main concern is that there be an unambiguous way to spell it. At first glance, it looks like gate myspecialgate(r, s, t) q0, q1; is indeed a good choice. We should think carefully about whether to require I imagine that how linking works will depend on the details of particular tool chains. |
Good points, @jlapeyre I would point out that A gate definition in OpenQASM 3 is somewhat like a function declaration in C. It seems to me semantically unambiguous to treat gate declarations that lack definition bodies like C function prototypes. Or am I missing the point? |
It seems semantically unambiguous to me too. I'm just not super confident that I am not overlooking something. I was trying to think of any possible conflicting future change... maybe something like |
@jlapeyre What are the use cases of such an undefined gate you have in mind? A gate specifies a unitary operation to be performed, not how the gate should actually be implemented. So gates are from one point of view already all external functions that specify the "API" they provide (i.e. the unitary they are supposed to perform). Is there a good use case for a gate whose behaviour is completely undefined? And why not just define the unitary? I guess what is missing is a way to specify gates whose behaviour is either not unitary or not entirely specified by the unitary operation. For example, one cannot define a I'm not sure whether OpenQASM should be extended to include this or whether this belongs in the pulse level language. My own imagined use cases: Perhaps extending gates in this way is a good idea for OpenQASM. E.g. It might be worthwhile to express |
I think we may be talking about two different things. Let me give an example of what I am talking about. I want to run a circuit specified in OQ3 on a backend. Suppose for some reason I need, as an intermediate step, to represent the circuit as as a Qiskit Suppose I want to use a include "stdgates.inc";
qubit q0;
qubit q1;
cx q0, q1; What happens when I send this to Qiskit? It is approximately the following. Qiskit will use the new rust "parser" as the compiler frontend. The frontend is meant to work with many backends, so it doesn't know about Qiskit. When the frontend sees the Now suppose instead that I did the following: qubit q0;
qubit q1;
cx q0, q1; In this case, long before Qiskit sees anything, the frontend will record an error saying that the gate Now suppose there is some other gate in the Qiskit library that I want to use, say include "stdgates.inc";
qubit q0;
qubit q1;
iswap q0, q1; Recall that the frontend doesnt know anything about Qiskit. The frontend sees that The way that this is typically solved for compiler tool chains is to allow a declaration of the minimal properties of gate iswap a, b;
qubit q0, q1;
iswap q0, q1; And the OQ3 spec would say that this declares that the symbol If you really don't want gate declarations, then you have design a particular, ad hoc, beside-the-spec convention for a particular backend. Here are some ideas First, regardless of solution, even using declarations as proposed, in order to specify that we want to "link" to Qiskit's extended standard library, Qiskit defines a pragma or allows flags to its import function. Or maybe just decides that it is always linked by default.
Following is a pretty bad solution, you can probably skip it.
This response has not been succinct, but I hope it sheds some light on the problem I see. |
@jlapeyre Thank you for the explansion! I am fine with long. In C if one wanted to link to an external function one would supply a header with a forward declaration. In OpenQASM that head is currently the full gate definition. I.e. From the language perspective the unitary behaviour is currently part of the signature of the gate and the implementation is always somewhere else. Currently I'm not entirely against having "extern" gates In the end, what you're describing seems to be a request to the compiler to use an opaque get implementation that will be supplied later and currently that is closest to Perhaps in the end the question is: Do we add extern gate to OpenQASM 3 or extern defcal to OpenPulse or even OpenQASM? |
I agree this is the meaning according the spec. And I would prefer that it stay that way. Any other meaning would be a hack agreed on between the QASM programmer and a particular compiler. Currently we use this hack for the Qiskit importer. I also use it all over the place in tests of the frontend as well, because I need to express the protocol for a gate without its definition and I have no better way to do it. But, at least for gates in the standard library, this hack will no longer be necessary in the frontend and importer because of the recent PR Qiskit/openqasm3_parser#185 . This PR is in line with the spec and is practical. I think one difficulty is that OQ3 is intended to be used for a broad range of goals. It seems that being able control quantum hardware at a low level is essential to its main use case. But it's only part of its main use case, if I understand correctly. For example here: openqasm/source/language/pulses.rst Lines 256 to 267 in 17dedfd
I guess that the low-level description is supplied in case the backend wants to actually send this gate to specific hardware (and recently calibrated!) And the more abstract description is supplied in case, at some level above the pulse descriptions, the compiler wants to reason about the gate and account for it in optimizations. But there are many valid use cases that do not need both of these definitions. Many users who don't know or care about calibrations might use OQ3 as an input format to Qiskit or some other compiler. Maybe they have a program that exports circuits as OQ3. If such a user wants to use gates in the standard library they don't need to supply a definition in OQ3, (this will be soon be made official in the OQ3 spec). They trust that Qiskit knows best how to represent the standard gate at all levels, for optimization, as well as pulses. Here is a feature that I imagine might be very attractive to users; I expect someone might ask for it. (I am repeating what I wrote in a previous comment, but with a different angle) The user asks "I want to send an OQ3 circuit to Qiskit that uses a gate from Qiskit's library that is not in the OQ3 standard library. How can I do this?". It's important to note that this user does not know or care about gate calibrations. I would implement this feature in the Qiskit importer as follows. Implementation with no gate declarations without definitions allowed in OQ3First, I would provide a flag in the importer that "links" the qiskit (extended) library. This request to link means the following. The importer reads statements as some data structure from the frontend. Every time it sees a gate call, it checks if it has seen this gate before (the gate is identified by an integer). If not, it checks the extended library. If it does not find the gate name there, it looks for a gate definition in a previously read statement from the frontend. If it does not find a definition, importing halts with an error. If it did find a definition, it caches the location for reuse the next time it sees a call to the same gate. Second, I would instruct the user to include in their OQ3 file a definition for the gate like this gate iswap a, b {} I would explain to the user that they could put anything in the body that they want, but that the cleanest, and least wasteful of resources, is to leave the body empty. The user trusts that Qiskit knows how best to represent this gate in any particular situation. But the user must include a definition, otherwise semantic analysis in the frontend will fail. This would be a fairly workable solution. But here are some disadvantages.
Implementation with simple gate declarations allowed.Now suppose that OQ3 does allow gate declarations with no definitions. I would implement access to the Qiskit extended library like this: I would not need to instruct the user on how to write the OQ3 input file. Because this is now part of the spec. The user would would write for example gate iswap a, b;
...
iswap q[0], q[3]; Alternatively Qiskit could provide an include file with these definitions. The include file would contain lines like include "qiskit_extended.inc";
...
iswap q[0], q[3]; I would again instruct the user to set a provided flag to link the Qiskit extended library. But the linking would work differently. All the disadvantages in the implementation above would disappear, and there would be additional advantages. For example
|
This all seems to have gotten way too complicated. Could you do:
and completely define the gates fully (i.e. specify the unitary they implement) in |
Aside 1: Defining a gate by just its name seems a bit fraught. There are already varying conventions around details of how a gate with a particular name is defined. Aside 2: Are there any Qiskit gates that should just go into Aside 3: Regarding the |
Yes. That is more or less one of scenarios I mentioned above. It puts a burden on the user, a burden on the designer of the importer, and introduces a class of bugs. At the same time, it provides no advantages over allowing extern declarations. Also, since the supplied definitions are completely ignored, the optimization of this process (which the user will certainly do once they realize it works) leads to supplying empty definitions. One might instead insist on the point and require the that user supply full gate definitions, and require that the importer (Qiskit, tket, etc.) does not discard these definitions but rather uses them. This still puts a burden on the user. The user has to choose a representation of the unitary, make sure it is coded correctly, and possibly optimize it. It doesn't put a burden on the importer (Qiskit, tket, ...) because they have to support gate definitions in any case. But now instead of being explicitly instructed to use the gate in the Qiskit library called
I agree 100%. I'm not in favor of OQ3 associating unitaries with gate names beyond what is already done for builtins and the standard library. In the present case, I declare a gate I might use a tool that manipulates circuits and exports OQ3. And the tool includes a gate called If I use a circuit-creation tool that exports include "qiskit_extended.inc";
gate SOMEGATE q {
somegate(q);
gphase(pi / 4);
} And of course, again, tell the importer to use the extended library so that I know exactly what
I don't know of any, but I haven't reviewed them either. Ideally before including another gate, I'd like to see that it is widely used by a number of compilers, Qiskit, tket, bloquade, what have you. How urgent is this?From my perspective, implementing extern gate declarations is not urgent. Being able to effectively have extern declarations for the standard library takes the pressure off. For other gates, I can continue to use the hack of empty definition wherever possible. If OpenQASM 3 becomes more widely used as an exchange format, extern gate declarations will be forced on us. Further development of the rust front end and the Qiskit importer may also make the issue more important. But since we will have to face this sooner or later, I think it's a good idea to start thinking about it now. |
Summarizing my current view, partly for myself:
|
I believe our intent when removing the
I think the above discussion is about something else, though – namely, connecting to an external tool's gate library while avoiding some kind of unitary matching and instead wishing to match by label instead. I agree that for performance reasons a user may desire this behavior, but I don't see why new language semantics would be required to achieve it. Instead, having your importer (optionally) inject a
so that those symbols are guaranteed to exist seems sufficient. |
I think while in general the contents of defcal are defcalgrammar-specific, having a grammar-independent way to indicate external linkage is valuable. |
There is no way to declare a gate without defining it.
In particular, there is no
extern
for gates.EDIT: The discussion of
stdgates.qasm
stdgates.inc
here is a red herring, because it is required to be supported in a precise way. This issue is relevant for other, non-standard, gate libraries.stdgates.inc
is expected to contain definitions. For example Qiskit'sstdgates.inc
contains definitions in the terms of the two built in gates. When importing into Qiskit, there is, in the typical case, no need to parse the definitions. A declaration will do.At the moment, it seems
gate rz(t) q {}
, is good enough. But it has to be interpreted specially by Qiskit, rather than as a gate that does nothing.If this were C, you would be required to include
extern
declarations and then link to a library. But details of linking and the library are not part of the language. For example#include <stdio.h>
does not require explicit linking in gcc. (I am not sure that the last two sentences are complete and/or correct) So I think can allowextern
for gates and then your compiler/transpiler toolchain is responsible for ensuring that definitions are found.See also
The text was updated successfully, but these errors were encountered: