We're delighted to announce our partnership with NVIDIA on a first-of-its-kind architecture for high-performance and low-latency quantum-classical computing.
< Back to Blog

A Novice Quantum Programmer’s Guide to QUA, or How I Found My Quantum Love Language

Elsie Loukiantchenko

Quantum Marketing Associate
June 1, 2021

Jump to:

Articles you might like

Never miss a Quark!
Sign up for the Newsletter

Subscribe >

Thanks for subscribing!

I’ll start this post with a small disclaimer: my relationship status with coding is a firm “it's complicated”. It’s been a rollercoaster of bouts of love and excitement, and moments when I vowed to never open another Vim terminal ever again. I love coding, but I’m not sure coding feels the same about me. Yet despite all of this, I’m always drawn to try again and again.

When I first set my eyes on QUA, I prepared myself for another lover’s tryst. I armed myself with a notebook, a stable internet connection, and a fully charged battery. I even had a bottle of wine ready for me if things didn’t go as well as I was hoping. It was our first encounter, after all; I was a little nervous.

But to my surprise, QUA was everything I’ve ever wanted from a programming language. It was very intuitive and easy to use. I didn’t have any unexplained bugs or errors to parse through, no mixed signals to try to understand. QUA was adaptive, comprehensive, and did exactly what I wanted it to do.

In all seriousness, QUA has been a great quantum computing programming language to learn. It is very easy to write pulses, generate measurements, and perform computation. As physicists, we can be quite hesitant about learning a new language. The time needed to get fully acquainted seems daunting, and getting to the point of doing meaningful work takes a long time. But I’m here to show you how in just a few lines of code, you can create, send, and measure a pulse to your qubit of choice.

QUA’s essential structure is quite intuitive: first, define a pulse sequence, then play it, then measure it. It really is as simple as that. Let’s go through it step by step.

1) Define a Pulse Sequence

Let’s start with an easy example. Let’s say we want to create a pulse we send to qubit 1, which comes out of port 1 of the OPX+. We thus define a quantum element, which we dub "qe1". This element contains all of the important specifications of this one qubit we want to control. We can set the oscillation frequency at any value we want within the bandwidth of the device, which is about ~450 MHz. Right now, let’s say 5 MHz (we can later use an IQ mixer to send a higher frequency to the experiment). We call this sequence playOp and assign everything in the following way:

 "qe1": {
            "singleInput": {"port": ("con1", 1)},
            "intermediate_frequency": 5e6,
            "operations": {
                "playOp": "constPulse",

We now need to define the constant pulse "constPulse"

   "pulses": {
        "constPulse": {
            "operation": "control",
            "length": 1000,  # in ns
            "waveforms": {"single": "const_wf"},
    "waveforms": {
        "const_wf": {"type": "constant", "sample": 0.2},

And just like that, we’ve created a pulse sequence!

2) Play the Pulse Sequence

Alright, so we have our pulses - now what? Playing them is easy:

with program() as prog:
    play("playOp", "qe1")

That’s all it takes to play the "playOp" pulse on "qe1".

3) Measure the Result

Now, all we have to do is to read out the pulse. To do this we open a connection to the OPX+, specify the configuration, and then run the program. In this example, we will use the OPX+ simulator. This is a feature that allows the output of the device to be calculated in a cycle-accurate way even if we don't have access to the OPX+ (for example if someone else is using it at the moment). To use the simulator we need to pass the simulate method a SimulationConfig, which tells the simulator the number of clock cycles it needs to run. In this case, 1000 ns.

We thus say:

QMm = QuantumMachinesManager()

QM1 = QMm.open_qm(config)
job = QM1.simulate(prog, SimulationConfig(int(1000))) 

samples = job.get_simulated_samples()

Finally, you will have an output like this:

A short pulse, with a frequency of 5 MHz, with a 1000 ns duration.

We have thus created a short pulse, with a frequency of 5 MHz, with a 1000 ns duration. 

QUA can allow researchers to implement parametric pulses which can be synthesized, sent, and altered “on the fly”, instead of being uploaded first (such as with an AWG). For example, the frequency of the pulse can be changed whenever the heart desires, without any latency.

This is a simple example of how the QUA language operates and it doesn’t even begin to describe everything else you can do with our quantum control system, the Quantum Orchestration Platform. You can create feedback loops to keep your qubits in certain states, concatenate different pulses seamlessly, ramp the amplitude of your oscillations, and a myriad of other things. If you think it, the QOP can do it!

Curious to see more? Check out our use cases, highlighting how the QOP quantum control system and QUA work on various types of qubits, including superconducting qubits, NV & defect centers, and quantum dots. There you will find in-depth experimental descriptions in order to show you just how much you can do. We’re also working on making QUA open source, and a huge GitHub library of pre-written QUA code will soon be available to help you get started in performing your groundbreaking research.

Let’s ReQUAlibrate

We created QUA and the Quantum Orchestration Platform as quantum physicists for quantum physicists - so essentially, it was made with you in mind. We were tired of the limitations imposed on our research by existing control tools, so we built the quantum control system that would make the lives of quantum researchers like yourself as easy as possible. This is why once you start working with QUA, know that we will be with you every step of the way, ready to provide you with any guidance and support you may need. We want to see you succeed in your research, and will do everything in our power to help you do it. 

To sum things up, my first encounter with QUA was flawless. It’s been completely smooth sailing for me; I’m now beginning to understand that not all coding relationships are supposed to be difficult. I am sure you will have as great an encounter with QUA as I did. Whether you’re well seasoned in the world of coding, or you’re an experimentalist who’s gotten by without too much head-scratching about “what did I do wrong?”, you’ll enjoy seeing the functionality of QUA, and how great of a lab companion it can be. And if you have a challenging experiment you'd like to run and you want to see what it would look like with QUA, feel free to reach out. We’ll be happy to show you how your experimental dreams can come true, and introduce you to your newest perfect match in the process.

< Back to Blog

About the Author

Elsie Loukiantchenko

Elsie is a quantum physicist with a strong love for adventurous baking. Priding herself in listening to podcasts every moment she gets, you can usually find her working on Quantum Machines' scientific content or dancing to herself in her room.

Elsie is a quantum physicist with a strong love for adventurous baking. Priding herself in listening to podcasts every moment she gets, you can usually find her working on Quantum Machines' scientific content or dancing to herself in her room.

Never miss a Quark