Starting Off With Quantum Computing

Jasmine Tong
13 min readFeb 19, 2019

--

Revisiting the grade 5 black market on a quantum computer

10-year-olds act like their the next leader of a mafia gang or black market. Sometimes, they really seem like it to. When I was in grade 5, our societal hierarchy and dominance over the snack-black market were determined by the most important thing thought possible. Your secretive placement of massive, strapping warships…and the cunning, strategic firing of missiles — all in the riveting game of Battleships.

The lunch bell was like the ring of a national emergency, notifying all civil servants to transform our surroundings from a workspace to an arena; battles in the middle, vendors on the side. Classmates rummaged through their bags, setting up lunches and snacks in preparation for the greatest trade-offs that will satisfy our gluttonous mouths.

Personally, I sucked at the dumb board game. A mere observer, I had to rely on good ol’ communication and persuasive skills if I wanted to trade my snacks for those tasty gummy welches.

Luckily, a regular board game of battleships was what was for mere mortals…

Presenting: Battleships on a Quantum Computor…or as I like to think of it…

Revisiting My Childhood, Round 2

If you’re unfamiliar with properties of quantum mechanics, don’t you worry. I came prepared. The following is an article detailing the basic characteristics of sub-atomic particles, or, the fascinating observations that define the crux of quantum mechanics.

I’ll give you a moment to expand your knowledge 😃.

Back already? Let’s do this.

Basic Pre-requisites

The only thing we really need to build this game is some understanding of the Python language, and Qiskit.

Qiskit is an SDK (software development kit) that is comprised of Python-based libraries, all created by IBM. This gives us normal people access to some extra (and pretty cool) quantum tools we can use to run quantum programs on prototype quantum devices and simulators.

TL;DR: gives us access to all these extra functions in order to run/create quantum circuits.

The quantum device/simulator we’re running our circuit on is IBM’s 5-qubit computer that they’ve uploaded onto a cloud, called the ibmqx4, available to dev’s worldwide to play with in order to satisfy our bouts of curiosity.

In the original tutorial of this game, James Wootton suggests downloading Jupyter Notebook in order to access his live tutorial via your browser, but you can also try to code this yourself or follow other devs on Github.

To download Qiskit, you can either browse through this tutorial:

or do what I did and PIP install it using the command:

pip install qiskit

If you already have QISKit, you’ll see something like this:

A bunch of ‘requirement already satisfied’ notifs = 👍

If you come up with an error, a great possibility is that you haven’t downloaded, or aren’t using, Python 3.5 or later, which QISKit requires PIP to use in order to install the QISKit packages.

To find out what version of Python you’re using, you can input this prompt:

python --version

to which you will receive the output below:

If your computer is using anything less, you’ll need to set the python command to use python 3.5 and later. To keep this article concise for those who already have QISKit, I’ve embedded a really clean article to help you PIP install QISKit:

Now to get started…

The Quantum-ness Behind Quantum Battleships

Understanding the basic theory behind this game isn’t actually too difficult. The game itself is a Japanese variant of the Western one we’re so used to. Each ship takes up only one space, but the number of missiles it takes to destroy the ship still differs. Our first ship will take one missile, the second, two, and the third, three.

Representing these ships will be qubits. Imagined like this:

Each number represents a qubit in ibmqx4.

The numbers are arbitrary names for the placement of the qubits. You can change these yourself in your code.

Representing our missiles will be quantum NOT gates. Applying a NOT gate (or partialNOT) sets the qubits into superposition (ah- see why you needed to read that article?), by rotating the qubit about the Y-axis.

qc.u3(math.pi,0,0, q[0])  # a NOT being applied to a qubit
  • Where qc represents our quantum circuit, q represents our quantum register, and c, our classical register (all of which we will initialize at the beginning of our code)
  • q[0] is telling the program which qubit to apply the NOT to [this first qubit is referred to as q[0] in code, since computers start counting with 0]
  • math.pi is the NOT being implemented

The special thing about NOT gates is that we can apply a fraction of it, too. That’s how we’ll be attacking ships that take 2+ missiles to destroy.

The math.pi corresponds to the angle pi, or the 180° rotation, which enables the qubit to be rotated from the 0 state to a 1 state (and vice versa).

To rotate the qubit just a fraction of 180°, we simply need to apply the decimal representation of the fraction:

u3(0.5*pi,0,0)  # half a NOT being applied

Let’s go through our whole QISKit snippet:

q = QuantumRegister(1) # initialize a register with a single qubit
c = ClassicalRegister(1) # initialize a register with a normal bit
qc = QuantumCircuit(q, c) # create and empty quantum program
qc.u3(math.pi,0,0, q[0]) # apply a NOT to the qubitqc.measure( q[0], c[0] ) # measure the qubit

Here, we’ve created a quantum circuit with one qubit, and one normal bit, applied a NOT, then measured the qubit state.

The qubit q[0] is automatically initialized in the state 0. Since that’s the state of an untouched ship, and that’s the state we want to start with, no further preparation is required.

Some might wonder why we need to initialize a register with a normal bit if we’re running a quantum circuit. This is because…well…as cool as we like to believe quantum computers to be, humans can’t 100% understand what a quantum computer is actually doing, and needs normal, classical computers to comprehend and deal with the inputs and outputs of these big, fancy chunks of metal.

Since a full NOT is applied, the output should always be: c[0]=1.

Lastly, to measure the qubit, we tell q[0] to decide what state it wants to fall into (0 or 1), in which the result will be stored in c[1], ready to be processed by classical computers, and interpreted by our regular, binary brains. Then, this makes the value of c[1] the output of our code.

In the case where we want to apply half a NOT (say, for a ship that requires 2 missiles to be destroyed…

q = QuantumRegister(1)
c = ClassicalRegister(1)
qc = QuantumCircuit(q, c)
qc.u3(0.5*math.pi,0,0, q[0])qc.measure( q[0], c[0] )

…our qubit q[0] will be in the superposition state in between [0] and [1]. Once the circuit measures the qubit, it will decohere, forcing the qubit to display either a state of |0> or |1>.

It is because of this probabilistic nature of sub-atomic particles, that the program is usually run multiple times, to confirm the probability of the qubit being in a 50% state of |0> and |1>.

Making a Quantum Game

Finally…eh?

So, now that you’ve been run through how the game works, let’s get to actually making it 😄.

We’ll need to import IBMQ libraries to run our code on IBM’s quantum experience:

Importing everything we need to run code on the IBM’s Quantum Experience.

Next, to run the quantum program on a quantum computer, we register our IBMQ API code:

Like a password that allows us to access a big chunky piece of metal!

IBMQ.enable_account loads your account, while

If you need to learn how to do it, quickly look here:

Any quantum program is really a mixture of quantum and classical parts. This relates all the way back to how our non-quantum brains cannot compute quantum computations (hence our creation of this technology). In this game, conventional computers take care of jobs such as getting input from players and displaying the grid. The scripts for these are kept in a separate python file, which we then import:

module = another python program that allows you to import specific built-in functionality from another file

After importing our IBMQ libraries, registering our API, and importing our module, we are now ready to code this bad boi. Let’s go through what needs to occur:

  1. Display title screen
  2. Ask player if they would like to play on a real quantum device or a simulator
  3. Ask players where they would like to place their ships
  4. Allow players to drop missiles onto grid
  5. Create quantum program for both players
  6. Run through quantum program
  7. Apply NOT to selected missile placement
  8. Measure qubit
  9. Display grid/status of the game

Displaying the Intro/Title Screen:

Here, the title screen is simply called from the module:

So in my battleships.py file, I would type title_screen(), which will display:

Decodoku = original creator of this game, linked below :)

Ask_For_Device

Here, we ask the players if they would like to play on a real quantum device (through IBMQ), or on a simulator:

To extract maximum awesomeness, input y, (yes), and your program will run on IBM’s 5-qubit quantum computer, ibmqx4. This takes longer, though, because your moves will have to be queued behind other people tryna sample ibmqx4’s awesomeness.

If you’re looking to get a quickie Battleships fix, feel free to input n to simulate everything on your own device. (Still cool though 😙)

Ask_For_Ships

Now that we got the ball rolling, we can ask players to where they’d like to place their lumbering pieces of death savvy boats:

In the call ask_for_ships(), players are represented by [0], and [1], and ships by [0], [1], and [2].

shipPos represents where the locations of the ships are chosen by the players. Entries for both players (player=0 and player=1), as well as their 3 ships, are stored here.

shipPos[player][ship] stores which [ship] is placed where (0, 1, 2, 3 or 4), and by which [player].

In the string asking the player where they’d like their ships placed, a [+1]is added to the ship and player that’s because called, because although in computer language, it makes sense to start counting from 0, to regular humans, it sounds weird when player 0 is called for their turn.

The code checks for factors of human error as well, such as if the player does not select a valid position (0, 1, 2, 3 or 4), or if they try to place a ship on top of another ship. If the player tries to do either, the code recognizes the input as false, (in choosing = false) and will output a string telling them so. The code will then continue to ask the player for a position for each ship, until choosing = true (a valid answer is given).

Ask_For_Bombs

Once ships are locked and loaded, we can start allowing our excited trigger fingers to select a location for destruction.

Players are asked to choose a position to bomb.

Inputs will be validated and checked for whether or not the input is an integer (position.isdigit()), and if that integer is within the correct range of numbers: (0, 1, 2, 3 or 4), represented by if position in range(5):.

If the player has chosen an invalid input, choosing = false, and a string notifying them of this will be outputted.

If the input is valid, the information will be stored in bomb[player][position], which counts how many time a [player] has bombed a certain [position] over the course of the game.

Once missiles have been ordered into position by these powerful players, the quantum program will then run through these mighty general’s cunning missile placements.

Quantum Wars

Setting up the quantum program to simulate each play (grid) from each player.

…which consists of quite a few parts itself…

  1. Create two quantum programs to run
  2. Set up registers
  3. Add missiles of opposing player
  4. Calculate effectiveness of each missile, according to its position
  5. Add NOT to corresponding qubit
  6. Measuring said qubits
  7. Compiling the data to be run on a quantum computer
  8. Extracting the data

Each round necessitates two quantum programs. One for each player. Both programs simulate the actions on the grid for their corresponding players. In the code below…

Creating two quantum programs

qc is the array used to hold these programs for range(2) (two) players.

Next, is setting up our quantum and classical registers, as explained way up above in the NOT gate section of this article 😃.

Initializing qubits for our program

Each program is initialized with five quantum bits (qubits) and five classical bits. Since we have two programs for two grids, we can access them by calling the array according to the player it’s representing: qc[player]. (Except the [player] part calls either [player = 0] or [player = 1].

Applying missiles and assessing the damage according to qubit

for position in range(5):’ adds the missiles of the opposing player, according to the n positions selected.

Since the destruction of a ship is determined by the strength of each individual ship, a missile placed on a stronger ship will apply only a fraction of the damage.

In quantum terms, this means that a missile that lands on the first ship applies a whole NOT onto [0], half a NOT for [1], and a third of a NOT for the third ship, [2].

Then, frac = 1/(ship+1)

To apply a NOT, or a frac of a not, we can use:

…with this line, we can apply a frac of a NOT to the qubit in a certain [position].

When the carnage is complete, it’s time to assess the damage. Or…measure the damage…

This measure-ment command forces the qubit to choose between the states |0> and |1>, effectively ‘measuring’ each qubit. The results are then copied onto the registered classical bits, ready to be interpreted by humans.

All of the above is then compiled and run as a quantum program

The backend to be used was defined earlier when we asked the player which device to run on, and shots represents the number of times the program will run.

This is an important factor in our quantum program because as you know from The Fundamentals of Quantum Computing, quantum programs run on a probabilistic system, in which results are statistical and never a confirmed output.

By setting the amount of ‘shots', we set the amount of samples we want the quantum device to produce in order to calculate the statistics on the possibly very random outputs.

Finally, we can extract the data…

Here, the intelligence on the damage done to a player's grid are received and copied onto grid, with the results stored in grid[player] as a dictionary.

Display_Grid

At the end of every series of attacks, all generals want to see the effects of their dominance.

That’s what this call is for.

If this function is called, it means no one has won and game must still be on…

When the game has been deemed True, the program will check the damage on all the ships by looping over all strings of range(5) bits for each [player]. The same is done for over all the [position]s. Results are then sent to players [0,1].

The information is then displayed as a percentage:

Ships with a 95% damage done to them are destroyed because we need to allow for the possibility that each NOT gate will not apply an exact percentage of damage (quantum noise tings).

If adequate damage was done to a player’s grid…

…the game would = False, and

Game Over.

So that’s that! Battleships played on a Quantum computer. I’m pretty much ready to pull up into my old elementary school and defeat the hierarchy of epic navy generals and assert dominance with my laptop and a hoard of snacks.

I can’t take all the credit, though, because the original creator of this game is actually the magical qubit wrangler, Dr. James Wootton.

AMA:

Talking to people is awesome. Everyone has a lifetime’s worth of experiences and knowledge to share with others. So let’s share ’em 😄. Ask me anything or teach me something new through:

--

--

Jasmine Tong

I write about things I want to keep note of or feel strongly about. I can’t promise the knowledge of an expert, but I can promise something to think about.