Domain-specific languages using FLEQ¶
This section will illustrate some techniques for using quantum kernel expressions and compile-time lists to implement domain-specific representations of programs, collectively known as domain specific languages (DSLs).
For example, suppose a user wants to take as input a string indicating an
\(n\)-qubit basis state such as \(\ket{01+-}\), and prepare a QList
of length \(n\) in that state. The format of the input string can be thought
of as a simple DSL for specifying state preparations.
To implement such a DSL, a user must write a QExpr
function that takes as
input the DataList
and a QList
and returns a quantum kernel expression.
To start, the function stateToQExpr
below returns the quantum kernel expression corresponding to a single character, while multiStateToQExpr
recursively applies stateToQExpr
to each character in a DataList
.
QExpr stateToQExpr(qbit& q, const char c) {
return
qexpr::cIf(c == '0', qexpr::_PrepZ(q),
qexpr::cIf(c == '1', qexpr::_PrepZ(q) + qexpr::_X(q),
qexpr::cIf(c == '+', qexpr::_PrepX(q),
qexpr::cIf(c == '-', qexpr::_PrepX(q) + qexpr::_Z(q),
qexpr::cIf(c == 'R', qexpr::_PrepY(q),
qexpr::cIf(c == 'L', qexpr::_PrepY(q) + qexpr::_Z(q),
qexpr::exitAtCompile("prepState: Expected a character in the set {0,1,+,-,R,L}.")
))))));
}
QExpr multiStateToQExpr(const qlist::QList qs, const datalist::DataList src) {
return qexpr::cIf(qs.size() == 0,
qexpr::identity(),
stateToQExpr(qs[0], src[0])
+ multiStateToQExpr(qs>>1, src>>1)
);
}
Finally, the function prepState
checks the input DataList
and ensures it has the correct format, before stripping the beginning and ending characters that make up the ket syntax.
QExpr prepState(const datalist::DataList src, const qlist::QList qs) {
return
qexpr::qassert(src[0] == '|',
"prepState: Expected a datalist of the form |state>")
+
qexpr::qassert(src[src.size()-1] == '>',
"prepState: Expected a datalist of the form |state>")
+
qexpr::qassert(src.size() == qs.size() + 2,
datalist::DataList("prepState: Expected a state of size ")
+ datalist::DataList(qs.size()))
+
// Strip the ket from the datalist
multiStateToQExpr(qs, src("|",">") >> 1)
;
}
The function qassert
is defined in qexpr_utils.h
and will raise a
compile-time error if the boolean condition is false.
The full example is shown in the sample file state_preparation.cpp
(see
Code Samples).
While the prepState
function is rather straightforward, these features can be
generalized to deal with more advanced DSL features, including persistent state
and symbol tables. In these cases, a DataList
representing the current state
would be passed to each QExpr
function and updated, similar to the concept
of a state monad in functional programming.
For example, suppose a user needs to process some input DataList
into a
different form before it can be used to construct a QExpr
via a function
stateToQExpr
. Then the user may write the following function,
processInput
, which iteratively converts an input DataList
into a
DataList
of the correct form, before feeding the well-formed state to
stateToQExpr
.
QExpr stateToQExpr(datalist::DataList state);
datalist::DataList updateState (datalist::DataList state, const char c);
QExpr processInput(datalist::DataList state, datalist::DataList input) {
return qexpr::cIf(input.size() == 0,
stateToQExpr(state),
processInput(updateState(state, input[0]),
input>>1)
);
}