Why Qwerty? #
Qwerty is a new quantum programming language whose novel constructs such as literals for qubit states and the basis type allow programmers to create and trace quantum programs without needing to understand bra–ket notation or gate-based semantics. Qwerty is embedded in Python, allowing both intuitive circuit synthesis from classical logic and easy interoperability between classical and quantum code, making Qwerty a robust framework for mixed quantum–classical computation.
Qwerty differs from many other quantum languages in three aspects:
- Programs are expressed through basis translations instead of low-level circuitry;
- Quantum program behavior can be traced intuitively through language constructs without physics notation; and
- Hybrid quantum/classical programs are written in a popular programming language, both on qubits and on classical bits, either inside or outside qubit lifetime.
The figure below illustrates these differences by comparing the diffusion step of Grover’s search algorithm in circuitry versus in Qwerty. The Qwerty code directly expresses, “replace \( \ket{+}\!\ket{+}\!\ket{+}\!\ket{+} \) with \( -\!\ket{+}\!\ket{+}\!\ket{+}\!\ket{+} \) ,’’ whereas the circuit implementation requires significantly more explanation and expertise to understand.
Hello World: Grover’s in Qwerty #
To introduce Qwerty, we begin with implementing Grover’s well-known quantum search algorithm. Whereas a classical brute-force search through \( 2^N \) possibilities requires \( O(2^N) \) queries to an N-bit black box oracle, Grover’s algorithm needs only \( O(\sqrt{2^N}) \) queries. The Qwerty code for Grover’s algorithm begins on lines 3-5 (below) by defining an example oracle. For simplicity, the example oracle marks the bits \( 1010 \) as the answer. As the C-style syntax on line 5 demonstrates, Qwerty programmers express classical oracles with classical code instead of quantum gates.
1from qwerty import *
2
3@classical
4def oracle(x: bit[4]) -> bit:
5 return x[0] & ~x[1] & x[2] & ~x[3]
6
7@qpu
8def grover_iter(q):
9 return (q | oracle.sign
10 | 'pppp' >> -'pppp')
11
12@qpu
13def grover():
14 return ('pppp' | grover_iter
15 | grover_iter
16 | grover_iter
17 | measure**4)
18
19print(grover())
Grover’s algorithm consists of many iterations, each of which rotates the state
away from the space of wrong answers toward the space of correct answers.
Line 8 defines a single Grover
iteration as a Qwerty function named grover_iter
. (Applying the
@qpu
decorator to a function as seen on
line 7 indicates that the function is written in Qwerty, not Python.) Because the syntax
x | f | g
represents g(f(x))
in Qwerty, lines
9-10 pass
q
first through an embedding of the oracle
(oracle.sign
) and then the Grover diffuser
('pppp' >> -'pppp'
). The syntax oracle.sign
produces the
quantum form of the classical function oracle
needed by Grover’s
algorithm, which avoids the need to understand or prepare a
\( \ket{-} \)
ancilla.
The Grover diffuser on line 10 is
written as a basis translation, the fundamental state evolution
primitive in Qwerty. The basis translation 'pppp' >> -'pppp'
allows
the programmer to write the Grover diffuser by describing how the state should
change, i.e., that
\( \ket{+}^{\otimes 4} \)
should be replaced with
\( {-}\ket{+}^{\otimes 4} \)
, instead of by picking
specific gates that accomplish this transformation.
The procedure for Grover’s algorithm begins by preparing a superposition of all
possibilities. In this example, we have decided to
perform the search across all four-bit values; thus, line 14 prepares a superposition of all four-bit values using the qubit literal 'pppp'
.
Because 'p'
is an equal superposition of both bits '0'
and '1'
, a four-fold 'p'
state represents all combinations of four single-bit values.
In traditional quantum programming, this preparation of a
\( \ket{+}^{\otimes 4} \)
state would be performed by writing a for
loop with Hadamard gates,
but qubit literals are more succinct and express programmer intention more
explicitly.
On lines 14-17, the pipeline in grover()
pipes this initial
'pppp'
state through three Grover iterations and into a four-qubit
measurement in the computational basis. (Note the number of iterations must be
chosen carefully because otherwise one may rotate either too far past the space
of correct answers or not far enough from the space of wrong
answers.) The final line is ordinary Python code and calls the Qwerty function grover()
with typical Python function call syntax, demonstrating the seamless integration of Qwerty with Python.