Qiskit / openqasm3_parser

Parser and semantic analyzer for the OpenQASM3 language
Apache License 2.0
11 stars 12 forks source link

Find a way to handle externally defined gates #20

Open jlapeyre opened 10 months ago

jlapeyre commented 10 months ago

The OQ3 spec does not provide a way to declare that gates are defined externally. The closest thing to this is included files, for example stdgates.inc. But this file is meant to include not only gate declarations, but rather gate definitions.

We might expect that a backend has its own definitions of some standard gates. It would be useful if this could be indicated in an OQ3 program, much as an external function can be declared via extern. For example, we might use one of

extern gate crx(theta) a, b;
gate crx(theta) a, b;

On the other hand, the spec currently allows this syntax

gate crx(theta) a, b {}

However, this already has a meaning; a gate that does nothing. Nonetheless, in the short term, the latter is what we will use.

As a short term action item, we need to do something sensible with a stdgates.inc that makes declarations in this way.

Example dummy or "declaration" file.

// OpenQASM 3 standard gate library

// phase gate
gate p(lambda) a {}

// Pauli gate: bit-flip or NOT gate
gate x a {}
// Pauli gate: bit and phase flip
gate y a {}
// Pauli gate: phase flip
gate z a {}

// Clifford gate: Hadamard
gate h a {}
// Clifford gate: sqrt(Z) or S gate
gate s a {}
// Clifford gate: inverse of sqrt(Z)
gate sdg a {}

// sqrt(S) or T gate
gate t a {}
// inverse of sqrt(S)
gate tdg a {}

// sqrt(NOT) gate
gate sx a {}

// Rotation around X-axis
gate rx(theta) a {}
// rotation around Y-axis
gate ry(theta) a {}
// rotation around Z axis
gate rz(lambda) a {}

// controlled-NOT
gate cx c, t {}
// controlled-Y
gate cy a, b {}
// controlled-Z
gate cz a, b {}
// controlled-phase
gate cp(lambda) a, b {}
// controlled-rx
gate crx(theta) a, b {}
// controlled-ry
gate cry(theta) a, b {}
// controlled-rz
gate crz(theta) a, b {}
// controlled-H
gate ch a, b {}

// swap
gate swap a, b {}

// Toffoli
gate ccx a, b, c {}
// controlled-swap
gate cswap a, b, c {}

// four parameter controlled-U gate with relative phase
gate cu(theta, phi, lambda, gamma) c, t {}

// Gates for OpenQASM 2 backwards compatibility
// CNOT
gate CX c, t {}
// phase gate
gate phase(lambda) q {}
// controlled-phase
gate cphase(lambda) a, b {}
// identity or idle gate
gate id a {}
// IBM Quantum experience gates
gate u1(lambda) q {}
gate u2(phi, lambda) q {}
gate u3(theta, phi, lambda) q {}
jakelishman commented 10 months ago

I'm not sure a parser needs this? The existing gate with definition mechanism is fine: the mapping to Qiskit objects is handled purely by Qiskit, and it's up to that to verify if a symbol is compatible with being represented with a Qiskit built-in.

A backend can absolutely supply a definition file with empty definitions if it chooses, but the parser doesn't need any special handling for that.

jlapeyre commented 10 months ago

I'm not thinking about just the parser, but more about the language. I'm thinking of an analogy with C. If I want to call sqrt(x), I need

extern double sqrt(double x);
double x = 1.0;
sqrt(x);

Just sqrt(x); is not a semantically valid program because the the symbol sqrt is undefined (in a sense, it's "undeclared"). This is independent of the backend. (In practice, for C, math.h is tied to the backend).

In the same way, this is not semantically valid OQ3

qubit q;
h q;

because h is undefined. You wrote

backend can absolutely supply a definition file with empty definitions if it chooses

which to me implies that the definition/declaration of h is optional. In this case the program above is semantically correct. Then we need to add this to the OQ3 spec: gates do not need to be declared. Furthermore, as a consequence, a more-or-less general purpose parser cannot check that a gate call passes the correct number of angle args and qubit args.

We could say that gate h q {} is a declaration. But that should also go in the spec. We could instead consider this declaration to be an extension for a QASM to Qiskit transpiler. Then at a minimum, the qiskit importer would have to require that built in gates are declared this way. That is if we want to parser/analyzer (this repo) to be useful for more than just Qiskit.

Furthermore all the backends would have the same problem, and each would solve it in an ad hoc way.

In any case, in the near term, as we don't have even one consumer yet, I think using empty gate definition bodies is good enough.