The world’s leading publication for data science, AI, and ML professionals.

Programming in 3D: My First Steps into Quantum Computing

A world of computing in multiple dimensions!

Tutorial

Source: Stable Diffusion.
Source: Stable Diffusion.

I remember my first quantum experience

I was speaking at the Grace Hopper 2018 (GHC18) conference. I had just visited the incredibly crowded and overwhelming vendor expo, and was looking for place to sit for a few minutes.

As it turns out, I ended up sitting down to an introductory presentation from IBM Quantum on using Qiskit, an open-source quantum computing framework.

Peering into the looking glass

The presentation was a basic introduction into the concept of a qubit and superposition.

I had no idea what superposition was, and yet, I found the presentation absolutely enthralling.

Just imagine, the idea of a bit on a computer being able to represent both the values 0 and 1 at the same time.

How could this be possible?

While this ultimately started my foundation into quantum computing, it also opened my eyes to the idea of Programming at an entirely different level.

It felt like programming in 3D.

Programming in the quantum world

On a classical computer, bits are represented with a value of 0 or 1. This is an exclusive condition.

A bit can hold a value of 0 OR 1.

However, it can not be both 0 AND 1 at the same time.

A qubit on a quantum computer, on the other hand, can hold a value of 0 AND 1 (or a floating point value in between) at the same time.

Think about this for a moment

If we have two bits on a classical computer, we can represent one of the following values during a single CPU cycle: 00, 01, 10, 11.

However, two qubits on a quantum computer can represent those same values simultaneously. This means that you can process calculations with quadratic or exponential increases in speed!

Similarly to how two qubits can represent four different values simultaneously, with three qubits we can represent eight values. Likewise, with four qubits we can represent sixteen.

While a classical computer can process n calculations per n bits, a quantum computer can process an astounding 2^n calculations per n qubits!

With just 50 qubits you could process 2⁵⁰ calculations in a single CPU cycle.

This is equivalent to over 140,000 GB of data processed during a single run of the program.

Thinking in a higher dimension

Since quantum computing can process multiple states for each qubit simultaneously, you begin to think in an entirely different way when writing a program.

Instead of writing a program with a single bit and expecting it to result in a value of 0 or 1 for a particular calculation, you have to begin thinking in a range of percentages.

So, a qubit might be 0 about half of the time, and it might be 1 the other half of the time.

This sounds confusion, and it had me confused at first as well — in fact, it still does!

However, let’s consider a fun example to understand the core difference in programming a classical program to programming a quantum computer.

I say hello, you say goodbye

Let’s suppose that we want to write a program to output "Hello" or "Goodbye", depending on an argument passed in having the value of 1 or 3.

If the function is passed an input of 1, we output the word, "Hello".

If the function is passed an input of 3, we output the word, "Goodbye".

These two values are only one bit apart in binary (1 = 01, 3 = 11). We’re keeping the first, least significant bit, fixed to a value of 1. These two values serve as a convenient example for a quantum computer.

Let’s see how we would write a plain classical program with it.

def greeting(input):
  if input == 1:
    print('Hello')
  elif input == 3:
    print('Goodbye')

greeting(1)
greeting(3)

Hello Goodbye

This is programming at a two-dimensional level.

We have a function that we can understand and it takes a single numeric input. We use a conditional statement to check if the value is 1 or 3. We output the message accordingly.

Each time this function is executed, we know exactly what the output will be according to the input.

Let’s see what this looks like on a quantum computer.

Programming in 3D

We can use the Quantum Computing framework, Qiskit, to create our program, as shown in the following example.

# Create a quantum circuit with 2 qubits.
qc = QuantumCircuit(2)

# Initialize the simulator.
simulator = Aer.get_backend('aer_simulator')

# Invert the first qubit (q0) to a value of 1.
qc.x(0)

# Place the second qubit (q1) into superposition for a value of 0 AND 1.
qc.h(1)

# Measure the result.
qc.measure_all()
A quantum computing program for generating a 2-bit number of 01 (1) or 11 (3). The first qubit (q0) is set to a value of 1. The second qubit (q1) is in superposition with a value of 0 and 1. Source: Author, generated by Qiskit.
A quantum computing program for generating a 2-bit number of 01 (1) or 11 (3). The first qubit (q0) is set to a value of 1. The second qubit (q1) is in superposition with a value of 0 and 1. Source: Author, generated by Qiskit.

The above program uses two qubits. Just like our classical program using an input of 1 or 3 to output a message, we can represent the same two values on a quantum computer by using two qubits.

Since both of the values in binary, 01 (1) and 11 (3), require the least-significant bit to be a value of 1, we invert the first qubit (using the X-gate) to hold a value of 1.

Now, here comes the amazing part

Our quantum program can hold two different values at the same time!

While the least significant qubit (q0) is fixed to a value of 1, the most significant qubit (q1) will hold a value of both 0 AND 1, effectively representing the integer 1 or 3. If this qubit ends up measuring as a value of 0, the resulting binary will be 01, and thus result in an integer of 1. If the qubit measures a value of 1, the resulting binary will be 11, and result in an integer of 3.

Together, the two qubits are virtually able to represent both the numbers 1 and 3 at the same time!

Let’s run the program and see what the output looks like.

# Execute the circuit.
job = execute(qc, simulator)
result = job.result()
counts = result.get_counts()

{’11’: 526, ’01’: 498}

A quantum computer outputs the number of times that the two qubits measured a value of 11 or 01. In both cases, notice how only the most-significant qubit (the one towards the left) is changing value.

This is the qubit (q1) that we placed in superposition – and this is the part where it feels like programming in 3D!

We’re no longer considering a single value. Instead, we now have to think about multiple values. Specifically, we have to think about both 1 and 3 as an input into our greeting program simultaneously.

The distribution of results for 1 or 3 on a quantum computer. Source: Author.
The distribution of results for 1 or 3 on a quantum computer. Source: Author.

Half of the time we will receive a 1 as input to our function, while the other half of the time we will receive a 3.

The message that our function outputs is tied directly to the chance that the second qubit (q1) ends up in a state of 0 or 1.

Running the quantum version

It takes significant thought to wrap one’s mind around the idea that a quantum program will return multiple values.

Since we will get back multiple values, we would need to change the greeting program to account for both cases.

def qgreeting(counts):
  if counts['01'] > 0:
    print('Hello')
  if counts['11'] > 0:
    print('Goodbye')

qgreeting(counts)

Hello Goodbye

The above program slightly modifies our original classical implementation, in that we are now checking if any of the resulting counts from measuring the quantum circuit have a count greater than zero. If so, we output the result.

Notice, the important distinction between the classical and quantum implementations of the greeting function:

  • The classical version required calling the greeting() function two times in order to output both messages.
  • The quantum version only requires a single call of qgreeting() to output the same messages.

Superimposing greetings

So far, we’ve modified the greeting program to check the counts from the qubit measurements. This let us output two messages from a single call, which helps us understand the quantum nature of multiple outcomes from our program.

However, since the qubits truly represent multiple values at the same time, instead of displaying two separate greetings, maybe we could superimpose the two greetings on top of one another!

def qgreeting(counts):
    message = ''

    # Define our messages.
    hello = 'Hello'
    goodbye = 'Goodbye'

    # Get the total number of measurements counts.
    total = counts['01'] + counts['11']

    # Calculate the percentage from the counts for "hello" and "goodbye".
    percent_hello = counts['01'] / total
    percent_goodbye = counts['11'] / total

    # Calculate the number of letters to use from "hello" and "goodbye".
    hello_chars = math.ceil(len(hello) * percent_hello)
    goodbye_chars = math.ceil(len(goodbye) * percent_goodbye)

    # Combine the two greetings into a single message.
    for i in range(hello_chars):
        message += hello[i]
    for i in range(goodbye_chars):
        message += goodbye[i]

    # The result is magic!
    print(message)

qgreeting(counts)

HelGood

Wow – we’re superimposing the two messages ("Hello" and "Goodbye") and combining them into a single greeting ("HelGood").

The number of letters output from each greeting comes from the measurement counts from each outcome of 01 (1) and 11 (3) in our quantum program.

Since our quantum circuit has a 50/50 chance of resulting in either outcome, it’s no surprise that we’re taking the first half of each greeting and joining them together.

Well, maybe that isn’t quite right either

While merging the two greetings together does, indeed, give a sense of the multiple values that the quantum program can simultaneously represent, it’s still a bit confusing.

Instead, let’s resolve the multiple quantum states into a single answer.

Flattening down quantum

As we’ve seen, the quantum qgreeting() uses a percentage of counts, resulting from the measurements of the quantum program in order to output a message.

Since we have measurement counts for each outcome, let’s just take the majority count and pass that as input to our original classical greeting method.

If the quantum program resulted in {’11’: 529, ’01’: 495}, we would use the binary result of 11, which equals 3, since it has the highest count.

Majority rules

Let’s use this method to run our original classical greeting method by selecting the value with the majority count and passing it as input to our classical program.

for i in range(6):
  # Execute the circuit.
  job = execute(qc, simulator)
  result = job.result()
  counts = result.get_counts()

  # Find the most frequent hit count.
  key = max(counts, key=counts.get)

  # Since the quantum computer returns a binary string (one bit for each qubit), we need to convert it to an integer.
  num = int(key, 2)

  # Display "Hello" or "Goodbye".
  greeting(num)

Hello Goodbye Goodbye Goodbye Hello Goodbye

This seems more realistic.

We’re now selecting the majority count and using that message as the output. This is actually called measuring in the computational basis state.

Notice, the output is returning different messages each time we execute the quantum circuit. This is due to the single qubit that we placed in superposition (on the most significant qubit).

We no longer have a completely deterministic program where we can be certain of the output. Instead, our program runs in the quantum universe!

Quantum computing power and complexity

It’s just fascinating how we can virtually represent simultaneous values in a quantum computing program.

However, it’s not too difficult to see how complex this can become when we start considering 3, 4, 10, 20, or 100 qubits in a program.

If only one qubit is placed into superposition (to have a 50/50 random chance of resulting in a value of 0 or 1), it may not be too difficult to grasp. After all, all of the other qubits will be a fixed value as initially assigned. Only the qubit(s) in superposition will hold the possibility for multiple values. However, when one or more qubits are in superposition, it becomes increasingly complex – but also increasingly more powerful!

In fact, superposition is at the core of gaining quadratic and exponential performance increases in quantum programs, compared to their classical counterparts. Since they can represent multiple states during a single CPU cycle, they can process far more permutations of bits than a classical computer.

Now, I hope it is becoming apparent how programming a quantum computer feels like programming in 3D. It’s, simply put, a completely different level from classical programming!

Does this sound like fun?

I hope that this initial discovery into quantum computing has piqued your interest as much as it did mine.

I certainly believe it’s this higher dimensional thinking that makes quantum computing so enticing, especially for programmers looking to develop their skills on an entirely new level.

You can download the complete code example for the greeting program here.

About the Author

If you’ve enjoyed this article, please consider following me on Medium, Twitter, and my web site to be notified of my future posts and research work.


Related Articles