Skip to content

OpenQASM extensions

Vlad Gheorghiu edited this page Jan 16, 2021 · 5 revisions

staq supports a number of extensions to the basic openQASM syntax. This page documents those extensions and provides examples of their usage.

Local ancillas

In addition to the global declaration of qubit registers in vanilla openQASM, staq supports defining local qubit registers within gate declarations, for use as ancillas. Local ancillas can be either 0-initialized, or dirty -- in some indeterminate state -- and in both cases are assumed (but not gauranteed) by the compiler to be returned to their initial state at the end of the gate.

To declare a local ancilla register, the keyword ancilla is used, e.g.,

gate foo a,b,... {
  ...
  ancilla anc[4];
  ...

By default ancilla registers are assumed to be 0-initialized. To allocate a dirty ancilla register, the keyword dirty precedes ancilla, as in

dirty ancilla anc[4];

Ancilla management The staq library provides tools for automatic management of ancillas during compilation. In particular, the inlining stage of compilation scans through the gate declarations and allocates a single global register the size of the maximum number of local ancillas in use at any point in the circuit. For instance, the following code

OPENQASM 2.0;
include "qelib1.inc";

gate foo a {
  ancilla b[1];
  ancilla c[1];
  cx a,b[0];
  cx a,c[0];
}

gate bar a {
  ancilla d[1];
  cx d[0];
}

qreg x[2];
foo x[0];
bar x[1];

inlines to

OPENQASM 2.0;
include "qelib1.inc";

gate foo a {
  ancilla b[1];
  ancilla c[1];
  cx a,b[0];
  cx a,c[0];
}

gate bar a {
  ancilla d[1];
  cx d[0];
}

qreg anc[2]
qreg x[1];
cx x[0],anc[0];
cx x[0],anc[1];
cx x[1],anc[0];

Note: The gates foo and bar above don't return their ancillas to their initial states after computation, while the compiler assumes (and uses them as if) they do. Ensuring that ancillas are properly cleaned after computation is left to the developer.

Oracle declarations

staq supports a new type of gate declaration in openQASM circuits for classical oracles defined in Verilog. Doing so lets the compiler know that the declared gate is a permutation of computational basis states, which can open up some optimizations or simulation methods, and moreover gives the developer the option to have the compiler synthesize an equivalent quantum circuit for them.

To declare an oracle, use the keyword oracle followed by the game identifier and list of inputs:

oracle OR in1,in2,out1 { "or.v" }

The body of the oracle should be the name of a Verilog file implementing the desired logic.

// or.v
module top ( a, b, c );
  input a,b;
  output c;
  assign c = a | b;
endmodule

Due to the reversibility of quantum oracles, there must be exactly one oracle input for every input and output of the given Verilog file. Oracle inputs are mapped to Verilog inputs and outputs sequentially, regardless of naming.

Synthesizing OR with default settings results in the following gate declaration:

gate OR in1,in2,out1 {
  ancilla anc[0];
  h out1;
  cx in1,out1;
  t out1;
  cx in2,out1;
  t out1;
  cx in1,out1;
  tdg out1;
  cx in2,out1;
  tdg out1;
  cx in2,in1;
  tdg in1;
  cx in2,in1;
  t in2;
  tdg in1;
  h out1;
  cx in2,out1;
}

Hint: the compiler looks for Verilog files in the directory it was called from. If synthesis of an oracle fails, check that the .v file is in the current working directory.

staq uses the EPFL logic synthesis library to provide support for synthesis of Verilog files, and generally any combinational Verilog circuits should be supported. More information on Verilog syntax can be found elsewhere, though small example showing the use of wires is given below.

// and_4.v
module top ( a, b, c, d, e );
  input a,b,c,d;
  output e;
  wire x,y;
  assign x = a & b;
  assign y = c & d;
  assign e = x & y;
endmodule
Clone this wiki locally