I completed all 5 exercises in the IBM Quantum Challenge 2021 — here’s how I did it! Part 1
Taking you on my journey through the 2021 IBM Quantum Challenge!
Hello Qiskitters, I am Luke Johnson, an IBM Quantum Ambassador and fellow Quantum computing enthusiast. I’m very excited to share with you my experiences of the 2021 IBM Quantum Challenge.
When I first saw the announcement for this year’s Quantum Challenge I was extremely excited! Having picked up the Intermediate badge in the last challenge, I was keen and motivated to go one step further and pick up the Advanced award this time. I’ve always found, since my first challenge in May 2020, that these challenges are a great way to really improve your knowledge and skills on both Qiskit and in Quantum Computing in general, and this years was no different.
So here goes…
‘5 quantum programming exercises for you to solve in a week to celebrate the 5th anniversary of IBM Quantum and 40 years of quantum computing’
Exercise 1: The Toffoli gate.
As soon as I saw that the first exercise was regarding Tommaso Toffoli’s reversible AND/NAND gate, it cast my mind back to the 2020 IBM Quantum Challenge, where this gate played a very important part in my solution to the ‘Lights Out’ problem. I was very interested to learn about its origins from the 1981 Physics of Computation conference (pictured below) and understand the inner workings of the gate, having only ever used it from its top level within Qiskit - qc.ccx!
The journey through classic logic gates, quantum circuits, quantum logic gates and specifically the rotations these gates caused gave a great introduction to the basics needed to complete the beginner exercises 1 and 2. The introduction of the truth tables idea also gave a much needed clue and helping hand which would become useful throughout for many beginners.
As soon as I saw the ask for this exercise, the competitive side of me was screaming in the back of mind “transpile, transpile, transpile” of course alluding to the transpile function which could take my .ccx circuit and tranpile it into the basis gates I wanted and move on to EX2. I resisted to getting one manually created set of gates that performed the Toffoli transformation, even if it wasn’t the best score possible (with the hunt for the Advanced badge at the forefront of my mind).
The first thing to notice and understand was combining two rotation gates that would cancel each other out, like an RX(pi/2) and a RX(-pi/2). But if we stuck between them a CNOT gate that when executed (ie the control was in the |1> state) the gates don’t cancel. I like to imagine that if we have a gate U, that we want to make a controlled U from it, then we must find single qubit gates let’s call them A, B and C such that CBA = I, but CXBXA = U. In the CC-U case I ‘guessed’ this must instead of being just one operation inside the two middle X gates instead be two operations as we need to cancel out the fact that one CX could be executed but the other not. Therefore I was left with combinations using the same notation: EDCBA (00 controls)= EXDCXBA(10 controls)= EDXCBXA(01 controls)= I (the identity matrix,ie do nothing) and EXDXCXBXA (11 controls)= U. The X’s I note here would of course be CX gates being executed with the controls noted in brackets. Next came half an hour or so messing around in the IBM Circuit Composer getting close but not quite there. The competitive side of me took over and I succumbed to the transpile voices giving me the final circuit pictured below (for a score of 72). This is something I noted down to return to after the challenge!
Working backwards looking at this I could see my logic above was correct. Straight onto EX2 and Peter Shor’s famous factoring algorithm!
Exercise 2 Shor’s Algorithm
Having surprisingly never taken too much time to look into Shor’s algorithm in too much detail, I was slightly worried this part could take me longer than the 1–2 hours estimated. But slowly working through the introduction and background, and being comfortable with the modular notation I got a good grasp of what Shor’s algorithm was doing. The exercise extends the controlled gate preview we were given in EX 1 by asking us to create a set of gates U that perform the modular transformations between the periods in the specific problem of factoring 35 on a quantum computer.
Again, the real detail in this problem is using a truth table, like the one pictured below, which someone in the #iqc2021 slack channel kindly provided, to try and create a circuit that performs those transformations.
Whilst remembering that qiskit and the IBM Circuit Composer write out the qubit states backwards… ie |01> = |q[1],q[0]>. Whilst we are on the topic, the slack channel and community around the challenge was fantastic. The participants were inclusive and supportive of one another, posting issues and tips within the channel as we went. Also a big shoutout to the mentors whose work was fantastic helping out those of us who were struggling at any point (as you’ll see soon)!
Working from the truth table, I started trying to create a circuit that took |100> to |110> which is the first transformation on the list (written like it would be in the circuit composer, |q[2],q[1],q[0]>)and is using q[2] as a control to performing this operation. I did this for each of the transformations separately, and noticed that it looked a lot like parts of my toffoli gate that had been decomposed/transpiled in the previous question but with and extra CX gate between one of the targets and the control at the end of the circuit. Using this as a guess I went back to the circuit composer to verify that this circuit would perform the transformations required (in the truth table) when the control was 1, and it would do nothing if the control was 0. Success!!! I then used my trusty transpile function to decompose this circuit into the U and CX gates that the exercise required.
Now came between 1 and 2 hours of wasting time… not realising that I simply needed to replicated this circuit twice for part b and four times for part c. Then compose them all together for the final part, having without realised it, already done the hard part. All that was left was to follow through the code to see your circuit successfully factorise 35!
Beginner badge in the bag and not even a day has gone by!!!
Exercise 3: Quantum Error correction.
Since the fantastic QC40 event which also celebrated the 40th anniversary of the physics of computation conference (well worth a watch), I had been interested to investigate error correction codes. In the first half of the event, Peter Shor introduces these error correcting codes and his process in discovering elements of them. Again the exercise really helps by first showing you a simple example which detects both bit flip errors (X gates where we don’t want there to be an X gate) and also phase flips. Being able to characterise these errors is the first step to trying to mitigate them from our real experiments on real hardware.
The exercise then presents you with a circuit comprised of code qubits, syndrome qubits and output classical bits. It then applies these stabiliser operations corresponding to the layout of the qubits that we consider. Below is the diagram of this layout which will turn out to be very important later in the exercise.
The first step is to understand that the qc_syn circuit takes our qc_init circuit (the initial set up state) and returns ‘0000’ so it undoes the qc_init circuit. However, if we add in either bit-flip errors or phase errors, then this will return a different string which will tell us the error that occurred within the circuit. We are also assuming that errors can only occur to two of our code qubits, code[0] and code[4]. This is where I noticed that the current notebook was only inserting a subset of the errors that the final challenge needed, and desperately scribbled around in my notepad to count the possible errors that we could see on 2 qubits with 2 different error types. Being very very careful I added these errors to the existing error function using the same structure of applying them to either our 0th or 1st error qubits. Now the backend result shows the output for each error and I’m happy that my circuit is performing the right function.
The next part of this question highlights the importance of the architecture of real quantum hardware. During my role and training as an IBM Quantum ambassador, I had investigated the different architectures of our chips. These are designed to reduce error rate and crosstalk. For this example we are using the retired device ibmq_tokyo for which you can see all of the properties and configuration by calling the backend.
Our objective is to edit our circuit along with a corresponding coupling map in the order listed if we call qc.qubits. This tells us which qubits in our backend to map our circuit qubits to when we want to run our experiment for real. This needs to allow all of the gates in our circuits to be performed on the Tokyo hardware with the desired connectivity.
It is now time to compare the qubit mapping above, to the actual connections in the hardware of IBM_tokyo. This is the part when you get to see my messy handwritten notes mapping the qubits in our circuit to Tokyo and noticing the issue with our circuit being performed.
You can see my circling of the ‘problem’ connecting qubit 2 and 7 in Tokyo, and therefore, using the default mapping [0,2,6,10,12,1,5,7,11], the connection between code[1] and syndrome[2]. I’d seen lots of conversations in the slack channel discussing at some point that we’d need to SWAP two qubits in order to allow any operations ‘connecting’ the two qubits that weren’t connected in Tokyo. I proposed this as a start point and got a confirmation from James Wooton ‘Qubit Wranger’ at IBM (also author of this challenge) in the slack channel.
The next step was to go to our circuits and see where they performed a CX between c[1] and s[2]. It turns out this only needs to be performed once in the qc_syn circuit when performing the right ZZZ stabiliser operation. So I knew somewhere here that I needed to use qc_syn.swap() to swap one of c[1] and s[2] to another qubit that was indeed connected to the other. So I had the choice (as you can see in my notes above) between swapping [7] and [6] or [2] and [6] before the operation, and then swapping them back afterwards. I went for the latter that swapped code[1] and code[2] (below).
The part I then tripped up on was not changing the qubit index inside the CX within the swap. So within the second line of the code above, the index of code[] qubit needed to be changed from 1 to 2 as we had swapped qubits 1 and 2. This circuit now swapped two of our qubits in order for them to be connected in the real hardware we were using!
This exercise really helped me understand not only characterising errors but also how the architecture of the backend is pivotal in the creation of an error mitigation process, and in general circuits!
To be continued for exercises 4 and 5…
The views expressed in this blog post are my own!