Compose quantum circuits for Amazon Braket
with the drag-and-drop magic of Quantum JavaScript (Q.js)
Are you drafting new quantum circuit designs? Composing, testing, and revising your circuit ideas has never been easier. Quantum JavaScript (Q.js) is a drag-and-drop quantum circuit composer and lightweight simulator that enables you to visually compose and experiment with quantum circuits. This post introduces Q.js and demonstrates how to use its library with Amazon Braket in a Jupyter Notebook Instance to drive actual quantum hardware.
The Q.js interface is a breakthrough in simplicity for quantum circuit composition. (It even runs comfortably on mobile devices.) Meanwhile, Amazon Braket is already a groundbreaking platform for both sophisticated circuit simulation as well as actual quantum circuit execution on real quantum hardware. When you, the intrepid quantum explorer, combine Q’s ease of use with Amazon Braket’s raw quantum power, you’ll find the whole is sweeter than the sum of its parts.
Using your AWS account, Amazon Braket access, and a special build of Q.js (linked below) you’ll be able to drive the 24 different quantum gate operations supported by Amazon Braket’s on-demand simulators—as well as Braket’s array of quantum hardware options. Let’s go.
Setup a Braket Notebook Instance with Q.js
- Download the Braket-ready Q.js bundles
We’re going to download a Braket-ready build of Q.js via a bundle.js
JavaScript file, and a bundle.css
Cascading Style Sheet file.
- For the JavaScript file, right-click on the following link (Control + click on Mac), and from within the resulting context menu select “Save Link As…”, then save this file to your desktop as
bundle.js
:https://raw.githubusercontent.com/stewdio/q.js/update-toAmazonBraket/build/bundle.js
- For the CSS file, we’ll likewise right-click on the following link, select “Save Link As…”, then save this file to your desktop as
bundle.css
:https://raw.githubusercontent.com/stewdio/q.js/update-toAmazonBraket/build/bundle.css
- Upload Q.js to your Braket Notebook
Now that you have a Braket-ready build of Q.js downloaded locally, we need to upload these two files into your Amazon Braket Notebook environment.
- Open up your own Braket Notebook Instance. (If you don’t have access to one, you can create one using the “Create Braket Notebook” guide.
- Once your Jupyter kernel is ready, click on “New” to create a new Jupyter-powered Braket Notebook.
- Click on “Upload” and upload both the
bundle.js
andbundle.css
files from your desktop to your Braket Jupyter folder. (Be sure these uploaded files are in the same folder as your current Notebook. Ever upload assets to the wrong Notebook by mistake and wonder why you can’t import them?!)
- Activate Q.js in your Braket Notebook
Your Q.js bundle files are now uploaded to your Notebook environment, but they aren’t active in the Notebook instance itself. The following code will load your Q.js bundle files into your Braket Notebook’s working memory, and use them to render the Q.js user interface in a subsequent Notebook cell.
- Add this code snippet to the first cell of your Notebook, then run it. (If you’ve saved these files using alternate names, replace “
bundle.js
” or “bundle.css
” with your respective filenames in the code below.)
from IPython.display import display, HTML
def javascript(file=None):
s = open(file).read()
display(HTML("<script type='text/javascript'>" + s + "</script>"))
def css(file=None):
s = open(file).read()
display(HTML("<style type='text/css'>" + s + "</style>"))
javascript('bundle.js')
css('bundle.css')
How’d that go? Q.js should now be in your Notebook’s working memory. We’re about to put that to the test.
- Run the following code in the next cell of your Notebook. This will generate a new Q.js circuit composer in the subsequent cell.
%%javascript
braket(element)
Your fresh circuit composer will look similar to this:
After running the command in Step B above, in addition to the circuit composer you’ll notice some code has appeared in a new cell, similar to the code snippet below:
from braket.circuits import Circuit
from braket.devices import LocalSimulator
import numpy as np
qjs_circuit = Circuit()
'''Uncomment following 2 lines to set up and use the on-demand simulator SV1 instead of LocalSimulator'''
#from braket.aws import AwsDevice
#device = AwsDevice("arn:aws:braket:::device/quantum-simulator/amazon/sv1")
device = LocalSimulator()
task = device.run(qjs_circuit, shots=100)
print(task.result().measurement_counts)
This Python code is automatically generated by Q.js, and likewise automatically updated each time you edit your circuit via the circuit composer interface. The first three lines of this codeblock import the required Braket SDK modules. The following line creates our qjs_circuit
object—which is currently an empty Circuit
because our Q.js circuit composer is still blank. (We’ll fix that!) As we drag and drop gates onto our Q.js circuit, this portion of code will update to incorporate those gates, in a similar fashion to this arbitrary example:
qjs_circuit = Circuit().h(0).cnot(0,1).phaseshift(2,1).z(3)
Compose a Bell State circuit with Q.js
So let’s build something already! Is it really quantum computing if we’re not using both superposition and entanglement together at once? A Bell state leverages two qubits to represent the simplest example of quantum entanglement. The distributed superposition is effectively a coin flip between two possible outcomes: Either both qubits evaluate to 1
, or both qubits evaluate to 0
. And here’s how we build it:
- Click and drag a Hadamard gate (represented by an “H” tile) onto the register for the second qubit (ie. onto the second horizontal row). Here we’ve arbitrarily placed our Hadamard gate at Moment 2 (represented by column 2) in the circuit diagram. The Hadamard gate will put its qubit into superposition.
- To make the Controlled-Not (“CNOT”) operation, first drag an Identity gate (represented by a “•” tile) and drop it onto the same qubit register (ie. the same horizontal row) as our Hadamard gate. Place it in the following Moment (ie. the next vertical column to the right).
- Next, drag a NOT gate (represented by the “X” tile) and drop it onto the same Moment (ie. the same vertical column) as our Identity gate, but on the subsequent qubit register (ie. the row below our Identity gate).
- Now we will combine the Identity gate and the Not gate to form a Controlled-Not (“CNOT”) gate. A Controlled-Not gate performs a Not operation on its target qubit register if, and only if, the control qubit is active. Click the Moment 3 label to select all gates in that moment, or select the Identity and Not gates individually by clicking on each of them. The “Control” button (“C”) in the Q.js toolbar will become active.
- Click the “Control” button (“C”) in the Q.js toolbar to combine the Identity and Not gates into one Controlled-Not gate. Our CNOT gate has the effect of entangling its control and target qubits. Bonus: We have distributed our superposition across our two entangled qubits. If that isn’t cool, what is?
- You know what—it’s silly to start building our Bell State on the second qubit. Let’s move it up to the first qubit! And while we’re at it, why are we starting on Moment 2? What are we waiting for? Let’s select the entire composition by clicking the diagonal arrow in the upper-left corner of the composer. Once all gates are selected, click and drag the group one register up, and one moment to the left, then release. See how easy it is to edit and reshuffle your circuit? And it works just as well on touch devices. Worried you’ll accidentally scramble your circuit with a stray touch or click? The Lock, Undo, and Redo buttons in the composer’s toolbar are there to keep you safe.
We’ve arbitrarily used four qubits for our circuit, so there are sixteen possible outcomes for any computation we craft on it. Here’s the probability breakdown for the Bell State that we’ve just created using the first two qubit registers:
1 |0000⟩ ██████████░░░░░░░░░░ 50% chance
2 |0001⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
3 |0010⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
4 |0011⟩ ██████████░░░░░░░░░░ 50% chance
5 |0100⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
6 |0101⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
7 |0110⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
8 |0111⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
9 |1000⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
10 |1001⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
11 |1010⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
12 |1011⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
13 |1100⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
14 |1101⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
15 |1110⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
16 |1111⟩ ░░░░░░░░░░░░░░░░░░░░ 0% chance
Run your circuit on Braket devices
Now we’re cooking. (Can you feel the heat? That’s metaphorical thermal inertia, baby!) You’ve successfully setup your Braket Notebook with Q.js, you can drag and drop quantum gates onto your circuit diagram and see the Braket code and lightweight simulation results update in realtime. You can even wrangle superposition and entanglement into your circuits with ease. Once you’re happy with your circuit composition, select the cell with that Q.js-generated Braket code and click the Run icon to execute your circuit program on Amazon Braket’s local simulator.
From Q.js to real quantum hardware
But we’re not here for simulation. We want to invoke actual quantum physics! To run your Q.js-composed circuit on real quantum hardware, simply reassign your device
variable to use the AWS Braket device you’d like to execute your composition on. For example, to run your composition on Rigetti’s 84-qubit Ankaa-2 system, replace your device
variable definition with the following:
device = AwsDevice('arn:aws:braket:us-west-1::device/qpu/rigetti/Ankaa-2')
For a full list of Braket’s supported hardware (including example code for selecting these devices), see Amazon Braket supported regions and devices.
Do you realize what you’re doing? You’re dragging and dropping a few icons around and that’s flipping quantum bits on some of the most advanced computation devices Earth has to offer. On the other side of your Internet connection there is actual quantum hardware reacting to your pointer clicks. You’re really going places today. And you look great in that shirt.
Advanced gates cheatsheet
Some Q.js gate operations require additional clicks to use, but have no fear—the interactions are so easy to remember that after you test drive them once, you’ll be comfortable tossing this cheatsheet right out. Ready?
Controlled gate
Need to flip the value of one qubit based on the value of another? Well this is easy—we just did it above in the Bell State example. Place an Identity gate (represented by a “•” tile) on your control qubit register at the desired location of your circuit. Then place a NOT gate (again, represented by an “X” tile) in the same Moment (ie. the same vertical column) as your placed Identity gate, but on your target qubit register. Now highlight these two gate operations by tapping or clicking on them, then select the “C” (Control) button on the Q.js toolbar. You will observe the two gate operations connect to form a Controlled-Not (“CNOT”) gate.
Swap gate
Sometimes your circuit design will require you to move a value off of one qubit register and onto another. You can accomplish this easily by swapping the values between any two qubits. Place an Identity gate (represented by a “•” tile) on each of the register lines for the qubits you’d like to swap, ensuring these two Identity gates occur in the same Moment (ie. the same vertical column). Highlight both of these Identity gates by tapping or clicking on them, then select the “S” (Swap) button on the Q.js toolbar. You will observe the two gate operations connect to form a Swap gate.
Parametrized gate
For parametrized gate operations (eg: Phase or Rotation gates), place the gate onto your circuit, then double-click the placed gate in order to view an input field for adjusting its parameter values.
Conclusion
Now you, too, can drag-and-drop your way from the Q.js circuit composer interface right onto actual hardware that harnesses the unparalleled computational power of quantum physics. What you choose to do with your new superpower is up to you. When you’re ready, check out the Braket Github Page for more advanced examples of quantum circuits that you can run on Amazon Braket. Happy coding.
Editor’s note
At the tail end of 2022, Amazon Braket folks reached out to me about co-authoring an official AWS blog post. They were specifically interested in showcasing how Quantum JavaScript’s graphic user interface could drive Braket. For me this was stellar—it was an opportunity to further legitimize a project that I held dear, but was in reality still a nights-and-weekends hobby. (I was doing it for the love of quantum.) While it appeared to be a mutually beneficial collaboration, I did have some reservations about teaming up with Braket…
Back in the spring of 2019 I’d begun building the foundation of Q.js. As I added new features, I’d show them off to friends and coworkers. I happened to be working for AWS in the emerging technologies group—and that became key. Our group’s director was impressed with what I’d made and let me in on something: Amazon was secretly building a quantum team. Would I like an introduction? (Yes, please.)
Shortly after, I was fielding Chime video calls from The King of all things Amazon Quantum. I recall him loudly pounding the desk on his side of the call as he emphasized how much he wanted Q.js integrated into Braket. (They’d tried building an interface. It’d been awful.) I had a rare combination of skillsets—a designer, but also a coder, and oddly in possession of basic quantum computing knowledge. (Enough to build my own simulator and composer interface, at any rate.) This is what’s required in order to truly innovate on quantum interfaces, after all. The prospect of transferring teams seemed almost inevitable—and I was quite happy about it.
An early demo of driving Amazon Braket via the Quantum JavaScript (Q.js) drag-and-drop interface inside a Jupyter Notebook. It’s a neat hack, but a true integration would have been far more impressive.
Confusingly, that pressured insistence on integrating Q.js into Braket never quite materialized into an offer to transfer teams—never mind a promotion or raise to celebrate my timely ingenuity. Additionally, I kept catching flak about this “red tape” preventing one division laboring for another; no Braket work allowed. The King wanted my free, open-source interface. No one on his team had the skillset to properly graft it on. I was happy to do it. But not on nights and weekends. This dragged on for months; the pestering over how Braket—while certainly not reliant on a graphic interface—would surely benefit from a good one. If only I’d do the work for free as a gesture; perhaps then some headcount would open up. (That’s not metaphorical, that was put to me directly.) Eventually Braket launched publicly; still no graphic interface.
This nonsense continued post-launch. I became frustrated enough that I seized an opportunity to confront an adjacent senior executive at the conclusion of an unrelated internal kickoff event. The auditorium’s spotlight had just relented as the house lights came up. He was still standing on stage as I leapt up alongside him; the last of the balloons and confetti slowly and awkwardly flittering down around us. If he and other execs agreed that they wanted my integration—which I was excited to work on—what exactly was the hold up? (It ought to be a simple internal transfer, no?) Again, something about “red tape” between divisions… But my help would still be appreciated. You’ve got to love AWS.
Having made no headway on what should have been a slam dunk, I realized my carer was stalled at Amazon. I quit. And had some fun in the process.
Fool me twice
So that was the larger context surrounding the offer to co-author an AWS blog post linking Quantum JavaScript with Amazon Braket. It’d been about 18 months since I’d left the company, but I still knew some of the folks crewing the stations. They were good people and I was open to what was sure to be a brief but rewarding collaboration.
I drafted multiple blog post revisions, integrated feedback received, and dined on the promise that we were close to publication. But then the feet-dragging began. Each response from Amazon’s side took longer to arrive than the last. Eventually I was told they’d “hit a snag” and had to “pivot the story line” but they would reach back out as soon as they “rephrased the content.”
Over a year’s passed since that last exchange and I think it’s safe to assume that the blog post offer has expired. But in the interest of demonstrating some of that early Q.js zeal, what you see above is a complete draft of that unpublished article. This revision has a bit more personality than what Amazon’s strict publication guidelines allow for (zero), but I think it serves this context better. (Are you not entertained?)
I think we’ve moved past the short-lived era of composing quantum circuits via these diagrams. The industry’s due for a complete rethink of what a circuit composer interface ought to be. I’d still welcome the opportunity to play in that space. (But not for free. I’ve done enough of that.)