├── 8ball.py ├── basic.py ├── clone.py ├── config.ini ├── deutsch_jozsa.py ├── hello.py ├── random-number.py ├── readme.md ├── search.py ├── superposition.py └── unicorn.py /8ball.py: -------------------------------------------------------------------------------- 1 | import qiskit 2 | from qiskit import IBMQ, ClassicalRegister, QuantumRegister, QuantumCircuit, execute, Aer 3 | from qiskit.providers.ibmq import least_busy 4 | from configparser import RawConfigParser 5 | 6 | # Setup the API key for the real quantum computer. 7 | parser = RawConfigParser() 8 | parser.read('config.ini') 9 | IBMQ.enable_account(parser.get('IBM', 'key')) 10 | 11 | # Setup 3 qubits. 12 | q = QuantumRegister(3) 13 | c = ClassicalRegister(3) 14 | qc = QuantumCircuit(q, c) 15 | 16 | # Place the qubits into superposition so the qubits no longer hold a distinct value, but instead are both 0 and 1 at the same time (50% 0, 50% 1). 17 | qc.h(q) 18 | qc.measure(q, c) 19 | 20 | # Using the qubits and their random value, form a response. 21 | def answer(result): 22 | for key in result.keys(): 23 | state = key 24 | print("The Quantum 8-ball says:") 25 | if state == '000': 26 | print('It is certain.') 27 | elif state == '001': 28 | print('Without a doubt.') 29 | elif state == '010': 30 | print('Yes - deinitely.') 31 | elif state == '011': 32 | print('Most likely.') 33 | elif state == '100': 34 | print("Don't count on it.") 35 | elif state == '101': 36 | print('My reply is no.') 37 | elif state == '110': 38 | print('Very doubtful.') 39 | else: 40 | print('Concentrate and ask again.') 41 | 42 | # Execute the job on the simulator. 43 | job = execute(qc, backend=Aer.get_backend('qasm_simulator'), shots=1) 44 | result = job.result().get_counts(qc) 45 | answer(result) 46 | 47 | # Execute the program on a real quantum computer. 48 | backend = least_busy(IBMQ.backends(simulator=False)) 49 | print("Running on", backend.name()) 50 | job = execute(qc, backend, shots=1) 51 | result = job.result().get_counts(qc) 52 | answer(result) -------------------------------------------------------------------------------- /basic.py: -------------------------------------------------------------------------------- 1 | import qiskit 2 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 3 | from qiskit import IBMQ 4 | from configparser import RawConfigParser 5 | 6 | # Setup the API key for the real quantum computer. 7 | parser = RawConfigParser() 8 | parser.read('config.ini') 9 | IBMQ.enable_account(parser.get('IBM', 'key')) 10 | 11 | # Setup a qubit. 12 | qr = QuantumRegister(1) 13 | cr = ClassicalRegister(1) 14 | program = QuantumCircuit(qr, cr); 15 | 16 | # Measure the value of the qubit. 17 | program.measure(qr, cr); 18 | 19 | # Execute the program in the simulator. 20 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator')) 21 | print("Running on the simulator.") 22 | print(job.result().get_counts()) 23 | 24 | # Execute the program on a real quantum computer. 25 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 26 | print("Running on", backend.name()) 27 | job = qiskit.execute(program, backend) 28 | print(job.result().get_counts()) 29 | -------------------------------------------------------------------------------- /clone.py: -------------------------------------------------------------------------------- 1 | # 2 | # Example of cloning a qubit that is currently in superposition to another qubit. 3 | # 4 | 5 | import qiskit 6 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 7 | from qiskit import IBMQ 8 | from configparser import RawConfigParser 9 | 10 | type = 'sim' # Run program on the simulator or real quantum machine. 11 | 12 | def run(program, type, shots = 100): 13 | if type == 'real': 14 | global isInit 15 | if not run.isInit: 16 | # Setup the API key for the real quantum computer. 17 | parser = RawConfigParser() 18 | parser.read('config.ini') 19 | IBMQ.enable_account(parser.get('IBM', 'key')) 20 | run.isInit = True 21 | 22 | # Set the backend server. 23 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 24 | 25 | # Execute the program on the quantum machine. 26 | print("Running on", backend.name()) 27 | job = qiskit.execute(program, backend) 28 | return job.result().get_counts() 29 | else: 30 | # Execute the program in the simulator. 31 | print("Running on the simulator.") 32 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator'), shots=shots) 33 | return job.result().get_counts() 34 | 35 | run.isInit = False 36 | 37 | # Setup qubits. 38 | qr = QuantumRegister(2) 39 | cr = ClassicalRegister(2) 40 | program = QuantumCircuit(qr, cr); 41 | 42 | # Set the first qubit to 1; this is the value we want to clone to the second qubit. 43 | program.x(qr[0]); 44 | 45 | # Put the first qubit into superposition. 46 | program.h(qr[0]); 47 | 48 | # To clone this qubit to the second, first undo the superposition. 49 | program.h(qr[0]); 50 | 51 | # Perform a CNOT between the qubits to copy the value from the first to the second. 52 | program.cx(qr[0], qr[1]) 53 | 54 | # Put the qubits back into superposition; the values are now cloned. 55 | program.h(qr[0]) 56 | program.h(qr[1]) 57 | 58 | # Measure the value of the qubits to confirm they are equal. We do this by first taking them out of superposition to get the actual value, then measuring the result. 59 | program.h(qr[0]) 60 | program.h(qr[1]) 61 | program.measure(qr, cr); 62 | 63 | # Execute the program. 64 | print(run(program, type)) -------------------------------------------------------------------------------- /config.ini: -------------------------------------------------------------------------------- 1 | [IBM] 2 | key = YOUR_API_KEY -------------------------------------------------------------------------------- /deutsch_jozsa.py: -------------------------------------------------------------------------------- 1 | # 2 | # The Deutsch Jozsh Algorithm: querying a oracle function that returns either 0 or 1 for all input values (constant) or returns exactly half 1 and half 0 for all input values (balanced). 3 | # A single cpu cycle on a quantum computer can solve this problem, compared with the best classical computing algorithm solution. 4 | # 5 | 6 | import qiskit 7 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 8 | from qiskit import IBMQ 9 | import numpy as np 10 | from configparser import RawConfigParser 11 | 12 | type = 'sim' # Run program on the simulator or real quantum machine. 13 | 14 | def run(program, type, shots = 100): 15 | if type == 'real': 16 | if not run.isInit: 17 | # Setup the API key for the real quantum computer. 18 | parser = RawConfigParser() 19 | parser.read('config.ini') 20 | IBMQ.enable_account(parser.get('IBM', 'key')) 21 | run.isInit = True 22 | 23 | # Set the backend server. 24 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 25 | 26 | # Execute the program on the quantum machine. 27 | print("Running on", backend.name()) 28 | job = qiskit.execute(program, backend) 29 | return job.result().get_counts() 30 | else: 31 | # Execute the program in the simulator. 32 | print("Running on the simulator.") 33 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator'), shots=shots) 34 | return job.result().get_counts() 35 | 36 | run.isInit = False 37 | 38 | # Set the length of the input array to check. 39 | n = 3 40 | 41 | # Choose a random type and value for the oracle function. 42 | oracleType = np.random.randint(2) 43 | oracleValue = np.random.randint(2) 44 | 45 | print("The oracle is constant.") if oracleType == 0 else print("The oracle is balanced.") 46 | 47 | # Create n + 1 qubits for the input array, all initialized to zero, with an extra qubit for storing the answer. 48 | qr = QuantumRegister(n + 1) 49 | # Create n registers for the output. 50 | cr = ClassicalRegister(n) 51 | program = QuantumCircuit(qr, cr) 52 | 53 | # Put all input qubits into superposition. 54 | for i in range(n): 55 | program.h(qr[i]) 56 | 57 | # Invert the last qubit (which stores the answer) and place it into superposition. 58 | program.x(qr[n]) 59 | program.h(qr[n]) 60 | 61 | # Apply a barrier to signify the start of the oracle process. 62 | program.barrier() 63 | 64 | if oracleType == 0: 65 | # This oracle is constant and returns oracleValue for all inputs. 66 | if oracleValue == 1: 67 | # Invert the answer qubit. 68 | program.x(qr[n]) 69 | else: 70 | # Keep the answer qubit as-is. 71 | program.iden(qr[n]) 72 | else: 73 | # The oracle is balanced and returns equal counts of 0 and 1. 74 | for i in range(n): 75 | # Set the qubit to return the inner product of the input with a non-zero bitstring. 76 | if (n & (1 << i)): 77 | # Apply a controlled-not between the input qubit and the answer qubit. 78 | program.cx(qr[i], qr[n]) 79 | 80 | # Apply a barrier to signify the end of the oracle process. 81 | program.barrier() 82 | 83 | # Undo the superposition for all input qubits. 84 | for i in range(n): 85 | program.h(qr[i]) 86 | 87 | # Measure the result of each input qubit. ??? 88 | program.barrier() 89 | for i in range(n): 90 | program.measure(qr[i], cr[i]) 91 | 92 | # The outputs (of length n) will be all 0 for a constant oracle, otherwise they will contain 1's for balanced. On a real quantum machine, the majority vote will be all 0's (due to error noise) for a constant oracle, likewise contain a mix balance of 1's for a balanced. 93 | # Simulator - The oracle is constant. 94 | # {'000': 1024} 95 | # Simulator - The oracle is balanced. 96 | # {'011': 1024} 97 | # Real quantum computer - The oracle is constant. 98 | # {'110': 2, '000': 879, '100': 75, '010': 29, '101': 5, '011': 1, '001': 33} 99 | # Real quantum computer - The oracle is balanced. 100 | # {'100': 163, '111': 238, '010': 88, '101': 73, '011': 264, '001': 69, '110': 69, '000': 60} 101 | print(run(program, type)) 102 | -------------------------------------------------------------------------------- /hello.py: -------------------------------------------------------------------------------- 1 | import qiskit 2 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 3 | from qiskit import IBMQ 4 | from configparser import RawConfigParser 5 | 6 | # Setup the API key for the real quantum computer. 7 | parser = RawConfigParser() 8 | parser.read('config.ini') 9 | IBMQ.enable_account(parser.get('IBM', 'key')) 10 | 11 | # Setup a qubit. 12 | qr = QuantumRegister(1) 13 | cr = ClassicalRegister(1) 14 | program = QuantumCircuit(qr, cr); 15 | 16 | # Measure the value of the qubit. 17 | program.measure(qr, cr); 18 | 19 | # Execute the program in the simulator. 20 | print("Running on the simulator.") 21 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator'), shots=100) 22 | counts = job.result().get_counts() 23 | print('Hello World! ' + str(counts)) 24 | 25 | # Execute the program on a real quantum computer. 26 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 27 | print("Running on", backend.name()) 28 | job = qiskit.execute(program, backend, shots=100) 29 | counts = job.result().get_counts() 30 | print('Hello World! ' + str(counts)) 31 | -------------------------------------------------------------------------------- /random-number.py: -------------------------------------------------------------------------------- 1 | # 2 | # A quantum random number generator. 3 | # Generates a random number of 2^x-bits in length by using x qubits. 4 | # 2 qubits = 4-bit random value 5 | # 3 qubits = 8-bit random value (1 byte) 6 | # 4 qubits = 16-bit random value (1 short, int16) 7 | # 5 qubits = 32-bit random value (int32) 8 | # 9 | # We can determine how many bits are required for a maximum integer value via: log2(n) + 1 10 | # Random number generation occurs with just a single CPU cycle on the quantum computer (no loops required). 11 | # 12 | 13 | import qiskit 14 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 15 | from qiskit import IBMQ 16 | from configparser import RawConfigParser 17 | import math 18 | 19 | type = 'sim' # Run program on the simulator or real quantum machine. 20 | 21 | def run(program, type, shots = 1, silent = False): 22 | if type == 'real': 23 | # Setup the API key for the real quantum computer. 24 | parser = RawConfigParser() 25 | parser.read('config.ini') 26 | IBMQ.enable_account(parser.get('IBM', 'key')) 27 | run.isInit = True 28 | 29 | # Set the backend server. 30 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 31 | 32 | # Execute the program on the quantum machine. 33 | if not silent: 34 | print("Running on", backend.name()) 35 | job = qiskit.execute(program, backend) 36 | return job.result().get_counts() 37 | else: 38 | # Execute the program in the simulator. 39 | if not silent: 40 | print("Running on the simulator.") 41 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator'), shots=shots) 42 | return job.result().get_counts() 43 | 44 | def bitCount(value): 45 | # Returns the number of bits needed to represent the integer value. 46 | return math.floor(math.log(value, 2)) + 1 47 | 48 | def bitsToInt(bits): 49 | # Convert a list of bits into an integer. 50 | out = 0 51 | for bit in bits: 52 | out = (out << 1) | bit 53 | 54 | return out 55 | 56 | def random(max): 57 | # Number of shots when we run the quantum program. 58 | shots = 1000 59 | 60 | # Determine how many bits are required for the maximum value. 61 | bits = bitCount(max) 62 | 63 | # Determine how many qubits are required to represent the number of bits, using the formula: 2^x = bits (where x is the number of qubits). For example, a value of 10 requires 4 bits which can be represented with 2 qubits (since 2^2 = 4). A value of 100 requires 7 bits which can be represented with 3 qubits (since 2^3 = 8). 64 | x = math.ceil(math.log(bits, 2)) 65 | 66 | # Create x qubits for the input array. 67 | qr = QuantumRegister(x) 68 | # Create x registers for the output. 69 | cr = ClassicalRegister(x) 70 | program = QuantumCircuit(qr, cr) 71 | 72 | # Place all qubits into superposition. 73 | program.h(qr) 74 | 75 | # Measure all qubits. 76 | program.measure(qr, cr) 77 | 78 | # Run the program for 1000 shots. 79 | results = run(program, type, shots, True) 80 | 81 | # Since the qubits are in superposition, they will have a 50% probability of returning 0 or 1 within each state. 82 | # We will get back 2^x results (with counts for the number of times each combination of 0s and 1s was measured). 83 | # Go through each result and determine a final 0 or 1 value for each bit by checking if the count is greater than the average probability. 84 | # The average probability = shots / outcomes (outcomes = 2^x). 85 | averageProbability = shots / math.pow(2, x) 86 | 87 | # Create an array to hold the random generated bits. 88 | randomBits = [] 89 | for key,value in results.items(): 90 | randomBits.append(1 if value > averageProbability else 0) 91 | 92 | return randomBits 93 | 94 | # Generate a random value from 0-100+. Note, this actually produces a max value of the max bits that can be represented for the specified number. For example, 10 uses 4 bits or 2 qubits with a max value of 15. 95 | randomValues = [] 96 | for i in range(500): 97 | randomValues.append(bitsToInt(random(100))) 98 | 99 | print(randomValues) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Quantum Computing Tutorial 2 | ========================== 3 | 4 | A set of simple programs for learning how to program a quantum computer. 5 | 6 | Read the tutorial [An Introduction to Quantum Computing](http://www.primaryobjects.com/2019/01/07/an-introduction-to-quantum-computing). 7 | 8 | ## What is it? 9 | 10 | Quantum computing is a technology based upon quantum physics and its inherent properties of superposition and entanglement. It brings a new paradigm to programming, where algorithms can be created that can process exponentially more data than classical computers that rely on transistor-based technology. 11 | 12 | This project contains a set of basic example programs to learn about programming a quantum computer. 13 | 14 | Several tutorial examples are included in this repository including the projects listed below. 15 | 16 | ## Quick Start 17 | 18 | To get started with quantum programming and the examples in this project, follow the steps below. 19 | 20 | 1. Install [Python3](https://www.python.org/downloads/). 21 | 22 | 2. Install [pip](https://pip.pypa.io/en/stable/installing/) if needed. To install pip, download [get-pip.py](https://bootstrap.pypa.io/get-pip.py) and execute it with the following command. 23 | 24 | ```bash 25 | python get-pip.py 26 | ``` 27 | 28 | 3. Install the required libraries for QisKit and the examples. 29 | 30 | ```bash 31 | pip install qiskit 32 | pip install ConfigParser 33 | ``` 34 | 35 | ### Hello World 36 | 37 | [hello.py](hello.py) 38 | 39 | A simple "Hello World" program in quantum computing. The program uses 1 qubit and simply measures it, finally printing out the text, "Hello World" and the measurement appended. 40 | 41 | ### Fly Unicorn 42 | 43 | [unicorn.py](unicorn.py) 44 | 45 | A game written on a quantum computer! 46 | 47 | Your magestic unicorn is ready for flight! 48 | After a long night of preparation and celebration, it's time to visit the castle in the clouds. 49 | Use your keyboard to fly up or down on a quantum computer, as you ascend your way into the castle. 50 | 51 | ```text 52 | =============== 53 | Fly Unicorn 54 | =============== 55 | 56 | Your majestic unicorn is ready for flight! 57 | After a long night of preparation and celebration, it’s time to visit the castle in the clouds. 58 | Use your keyboard to fly up or down on a quantum computer, as you ascend your way into the castle. 59 | 60 | 61 | ===================== 62 | -[ Altitude 0 feet ]- 63 | Your unicorn is waiting for you on the ground. 64 | [up,down,quit]: u 65 | You soar into the sky. 66 | Running on the simulator. 67 | {'0': 945, '1': 55} 68 | 69 | ===================== 70 | -[ Altitude 55 feet ]- 71 | Your unicorn is floating gently above the ground. 72 | [up,down,quit]: u 73 | You soar into the sky. 74 | Running on the simulator. 75 | {'0': 886, '1': 114} 76 | 77 | ===================== 78 | -[ Altitude 114 feet ]- 79 | Your unicorn is hovering just above the evergreen sea of trees. 80 | [up,down,quit]: 81 | ``` 82 | 83 | ### Superposition 84 | 85 | [superposition.py](superposition.py) 86 | 87 | An example of using superposition in quantum programming. This program contains three examples to demonstrate the properties of quantum superposition and entanglement. 88 | 89 | The first example measures 2 qubits in their initial states (all zeros) and prints the results. 90 | 91 | The second example creates a [Bell state](https://en.wikipedia.org/wiki/Bell_state) (|00> + |11>), (|00> - |11>), (|01> + |10>), (|01> - |10>). This is done by entangling 2 qubits, placing the first qubit into superposition (existing as 0 and 1 simulataneously with 50% chance of measuring either value), and finally measuring the results. The output should be half 00 and half 11. 92 | 93 | The third example demonstrates [superdense coding](https://en.wikipedia.org/wiki/Superdense_coding). This involves sending two classical bits of information (for example: 01) by only manipulating a single qubit. Suppose Alice wants to send Bob the message 01. This can be done by entangling the two qubits to create a Bell state of `00`. One qubit is given to Alice and the other is given to Bob. Alice can now manipulate her qubit to alter the resulting Bell state to indicate the value `01`. She can do this by inverting the value of her qubit (which is in superposition). She then sends Bob her qubit. Bob now reverses the entanglement and reverses the superposition of Alice's qubit. Bob can now measure the two qubits and obtain the value of `01`. In this case, Bob's qubit miraculously turns from a `0` into a `1`. 94 | 95 | ### Cloning a Qubit 96 | 97 | [clone.py](clone.py) 98 | 99 | An example of cloning a qubit that is currently in superposition to another qubit. 100 | 101 | This process involves setting the first qubit to a value of 1 (the value we want to clone to the second qubit). We then place the first qubit into superposition. To clone, we first reverse the superposition on the first qubit. Next, we perform a controlled-not operation between the two qubits, establishing an entanglement. We then put both qubits into superposition, effectively cloning their values. 102 | 103 | ### The Deutsch Jozsa Algorithm 104 | 105 | [deutsch_jozsa.py](deutsch_jozsa.py) 106 | 107 | An example of the Deutsch Jozsa Algorithm. This algorithm demonstrates how a quantum computer substantially differs from a classical computer by solving a problem in 1 cycle, that would take a classical computer much longer. 108 | 109 | License 110 | ---- 111 | 112 | MIT 113 | 114 | Author 115 | ---- 116 | Kory Becker 117 | http://www.primaryobjects.com/kory-becker 118 | -------------------------------------------------------------------------------- /search.py: -------------------------------------------------------------------------------- 1 | # 2 | # Grover's Search algorithm in quantum computing. 3 | # Brute-force password cracking by taking an n-bit code and checking against an oracle function until the correct code is found. 4 | # Unlike a traditional computer that would require 2^n-1 calls in the worst-case scenario, a quantum algorithm can solve this task in sqrt(2^n) calls. 5 | # A code of 64 bits could take a classical computer hundreds of years to solve, while a quantum computer could solve it in just a few seconds. 6 | # 7 | # This example uses a simple code of just 2 bits: 00, 01, 10, 11 8 | # In this case, we'll choose 01 as our secret code. 9 | # The oracle function knows the code. How fast can your algorithm break it? 10 | # 11 | # Reference: http://kth.diva-portal.org/smash/get/diva2:1214481/FULLTEXT01.pdf 12 | # Appendix A.2 13 | # 14 | # export PYTHONWARNINGS="ignore:Unverified HTTPS request" 15 | # python3 search.py 16 | # 17 | 18 | import qiskit 19 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 20 | from qiskit import IBMQ 21 | import numpy as np 22 | import operator 23 | import time 24 | import ast 25 | import sys 26 | from configparser import RawConfigParser 27 | 28 | type = 'sim' # Run program on the simulator or real quantum machine. 29 | shots = 1024 # Number of measurements (shots) per program execution. 30 | trials = 10 # Number of trials to run the experiment in performing Grover's search on a secret key. 31 | 32 | def run(program, type, shots = 1): 33 | if type == 'real': 34 | if not run.isInit: 35 | # Setup the API key for the real quantum computer. 36 | parser = RawConfigParser() 37 | parser.read('config.ini') 38 | 39 | # Read configuration values. 40 | proxies = ast.literal_eval(parser.get('IBM', 'proxies')) if parser.has_option('IBM', 'proxies') else None 41 | verify = (True if parser.get('IBM', 'verify') == 'True' else False) if parser.has_option('IBM', 'verify') else True 42 | token = parser.get('IBM', 'key') 43 | 44 | IBMQ.enable_account(token = token, proxies = proxies, verify = verify) 45 | run.isInit = True 46 | 47 | # Set the backend server. 48 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 49 | 50 | # Execute the program on the quantum machine. 51 | print("Running on", backend.name()) 52 | start = time.time() 53 | job = qiskit.execute(program, backend) 54 | result = job.result().get_counts() 55 | stop = time.time() 56 | print("Request completed in " + str(round((stop - start) / 60, 2)) + "m " + str(round((stop - start) % 60, 2)) + "s") 57 | return result 58 | else: 59 | # Execute the program in the simulator. 60 | print("Running on the simulator.") 61 | start = time.time() 62 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator'), shots=shots) 63 | result = job.result().get_counts() 64 | stop = time.time() 65 | print("Request completed in " + str(round((stop - start) / 60, 2)) + "m " + str(round((stop - start) % 60, 2)) + "s") 66 | return result 67 | 68 | run.isInit = False 69 | 70 | def generatePassword(): 71 | # Choose a random code for the oracle function. 72 | password = np.random.randint(2, size=4) 73 | 74 | # Convert the password array into an array of strings. 75 | passwordStrArr = np.char.mod('%d', password) 76 | # Convert the array of strings into a single string for display. 77 | passwordStr = ''.join(passwordStrArr) 78 | 79 | return password, passwordStr; 80 | 81 | def oracle(program, qr, password): 82 | # Find all bits with a value of 0. 83 | indices = np.where(password == 0)[0] 84 | 85 | # Invert the bits associated with a value of 0. 86 | for i in range(len(indices)): 87 | # We want to read bits, starting with the right-most value as index 0. 88 | index = int(len(password) - 1 - indices[i]) 89 | # Invert the qubit. 90 | program.x(qr[index]) 91 | 92 | def search(password): 93 | # Grover's search algorithm on a 4-bit secret key. 94 | # Create 2 qubits for the input array. 95 | qr = QuantumRegister(4) 96 | # Create 2 registers for the output. 97 | cr = ClassicalRegister(4) 98 | program = QuantumCircuit(qr, cr) 99 | 100 | # Place the qubits into superposition to represent all possible values. 101 | program.h(qr) 102 | 103 | # Run oracle on key. Invert the 0-value bits. 104 | oracle(program, qr, password) 105 | 106 | # Apply Grover's algorithm with a triple controlled Pauli Z-gate (cccZ). 107 | program.cu1(np.pi / 4, qr[0], qr[3]) 108 | program.cx(qr[0], qr[1]) 109 | program.cu1(-np.pi / 4, qr[1], qr[3]) 110 | program.cx(qr[0], qr[1]) 111 | program.cu1(np.pi/4, qr[1], qr[3]) 112 | program.cx(qr[1], qr[2]) 113 | program.cu1(-np.pi/4, qr[2], qr[3]) 114 | program.cx(qr[0], qr[2]) 115 | program.cu1(np.pi/4, qr[2], qr[3]) 116 | program.cx(qr[1], qr[2]) 117 | program.cu1(-np.pi/4, qr[2], qr[3]) 118 | program.cx(qr[0], qr[2]) 119 | program.cu1(np.pi/4, qr[2], qr[3]) 120 | 121 | # Reverse the inversions by the oracle. 122 | oracle(program, qr, password) 123 | 124 | # Amplification. 125 | program.h(qr) 126 | program.x(qr) 127 | 128 | # Apply Grover's algorithm with a triple controlled Pauli Z-gate (cccZ). 129 | program.cu1(np.pi/4, qr[0], qr[3]) 130 | program.cx(qr[0], qr[1]) 131 | program.cu1(-np.pi/4, qr[1], qr[3]) 132 | program.cx(qr[0], qr[1]) 133 | program.cu1(np.pi/4, qr[1], qr[3]) 134 | program.cx(qr[1], qr[2]) 135 | program.cu1(-np.pi/4, qr[2], qr[3]) 136 | program.cx(qr[0], qr[2]) 137 | program.cu1(np.pi/4, qr[2], qr[3]) 138 | program.cx(qr[1], qr[2]) 139 | program.cu1(-np.pi/4, qr[2], qr[3]) 140 | program.cx(qr[0], qr[2]) 141 | program.cu1(np.pi/4, qr[2], qr[3]) 142 | 143 | # Reverse the amplification. 144 | program.x(qr) 145 | program.h(qr) 146 | 147 | # Measure the result. 148 | program.barrier(qr) 149 | program.measure(qr, cr) 150 | 151 | return run(program, type, shots) 152 | 153 | for i in range(trials): 154 | # Generate a random password consisting of 4 bits. 155 | password, passwordStr = generatePassword() 156 | 157 | # Display the password. 158 | print("The oracle password is " + passwordStr + ".") 159 | sys.stdout.flush() 160 | 161 | # Ask the quantum computer to guess the password. 162 | computerResult = [] 163 | count = 0 164 | while computerResult != passwordStr: 165 | # Obtain a measurement and check if it matches the password (without error). 166 | results = search(password) 167 | print(results) 168 | computerResult = max(results.items(), key=operator.itemgetter(1))[0] 169 | print("The quantum computer guesses ") 170 | print(computerResult) 171 | count = count + 1 172 | sys.stdout.flush() 173 | 174 | print("Solved " + passwordStr + " in " + str(count) + " measurements.") 175 | -------------------------------------------------------------------------------- /superposition.py: -------------------------------------------------------------------------------- 1 | import qiskit 2 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 3 | from qiskit import IBMQ 4 | from configparser import RawConfigParser 5 | 6 | type = 'real' # Run program on the simulator or real quantum machine. 7 | 8 | def run(program, type, shots = 100): 9 | if type == 'real': 10 | if not run.isInit: 11 | # Setup the API key for the real quantum computer. 12 | parser = RawConfigParser() 13 | parser.read('config.ini') 14 | IBMQ.enable_account(parser.get('IBM', 'key')) 15 | run.isInit = True 16 | 17 | # Set the backend server. 18 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 19 | 20 | # Execute the program on the quantum machine. 21 | print("Running on", backend.name()) 22 | job = qiskit.execute(program, backend) 23 | return job.result().get_counts() 24 | else: 25 | # Execute the program in the simulator. 26 | print("Running on the simulator.") 27 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator'), shots=shots) 28 | return job.result().get_counts() 29 | 30 | run.isInit = False 31 | 32 | # 33 | # Example 1: Measure 2 qubits in their initial state, all zeros. 34 | # 35 | 36 | # Setup qubits. 37 | qr = QuantumRegister(2) 38 | cr = ClassicalRegister(2) 39 | program = QuantumCircuit(qr, cr); 40 | 41 | # Measure the value of the qubits in their initial state, they should be all zeros. 42 | program.measure(qr, cr); 43 | 44 | # Execute the program. 45 | print(run(program, type)) 46 | 47 | # 48 | # Example 2: Create a Bell state (|00> + |11>), (|00> - |11>), (|01> + |10>), (|01> - |10>): Entangle 2 qubits, with the first in superposition (existing as 0 and 1 simulataneously or 50% chance of either value) and measure the results, they should be half 00 and half 11. 49 | # 50 | 51 | # Setup qubits. 52 | qr = QuantumRegister(2) 53 | cr = ClassicalRegister(2) 54 | program = QuantumCircuit(qr, cr); 55 | 56 | # Place the first qubit into a superposition, existing as both 0 and 1 simultaneously. 57 | program.h(qr[0]) 58 | 59 | # Entangle the two qubits with a controlled NOT operator. If the first qubit is 1, the second qubit will be inverted. Depending on the initial qubit states, this results in the 4 Bell states (|00> + |11>), (|00> - |11>), (|01> + |10>), (|01> - |10>). 60 | program.cx(qr[0], qr[1]) 61 | 62 | # Sender: Invert the first qubit to set it from 0 to 1 (remember, we're trying to represent 01 by manipulating only a single qubit q[0]). 63 | # 00 I - Identity nothing to do 64 | # 01 X - program.x(qr[0]) 65 | # 10 Z - program.z(qr[0]) 66 | # 11 XZ - program.x(qr[0]) program.z(qr[0]) 67 | program.x(qr[0]) 68 | 69 | # Measure the value of the qubits, they should be equally 00 and 11, one of the Bell states. 70 | program.measure(qr, cr); 71 | 72 | # Execute the program. 73 | print(run(program, type)) 74 | 75 | # 76 | # Example 3: Superdense coding: send two classical bits of information (01) by only manipulating a single qubit: Reverse a Bell state: Entangle 2 qubits, with the first in superposition, then reverse the steps and measure the results, they should be all zeros. 77 | # The first qubit is owned by Alice. 78 | # The second qubit is owned by Bob. 79 | # Alice will modify her qubit qr[0] in order to end up representing 01 to Bob, then send her qubit to him. 80 | # Bob will reverse the entanglement and superposition of Alice's qubit and read the results, getting 01 from the qubits (his qubit miraculously turns into a 1). 81 | 82 | # Setup qubits. 83 | qr = QuantumRegister(2) 84 | cr = ClassicalRegister(2) 85 | program = QuantumCircuit(qr, cr); 86 | 87 | # Sender: Place the first qubit into a superposition, existing as both 0 and 1 simulateneously. 88 | program.h(qr[0]) 89 | 90 | # Sender: Entangle the two qubits with a controlled NOT operator. If the first qubit is 1, the second qubit will be inverted, otherwise it remains the same. 91 | program.cx(qr[0], qr[1]) 92 | 93 | # Sender: Invert the first qubit to set it from 0 to 1 (remember, we're trying to represent 01 by manipulating only a single qubit q[0]). 94 | # 00 I - Identity nothing to do 95 | # 01 X - program.x(qr[0]) 96 | # 10 Z - program.z(qr[0]) 97 | # 11 XZ - program.x(qr[0]) program.z(qr[0]) 98 | program.x(qr[0]) 99 | 100 | # Receiver: Repeat the controlled NOT operator, reversing the entanglement. 101 | program.cx(qr[0], qr[1]) 102 | 103 | # Receiver: Repeat the Hadamard, reversing the superposition state. 104 | program.h(qr[0]) 105 | 106 | # Receiver: Measure the value of the qubits, we should get back the original values. 107 | program.measure(qr, cr); 108 | 109 | # Execute the program. 110 | print(run(program, type)) -------------------------------------------------------------------------------- /unicorn.py: -------------------------------------------------------------------------------- 1 | # 2 | # Fly Unicorn 3 | # A simple quantum game where the player has to fly a unicorn to the castle. 4 | # 5 | 6 | import math 7 | import qiskit 8 | from qiskit import ClassicalRegister, QuantumRegister, QuantumCircuit 9 | from qiskit import IBMQ 10 | from configparser import RawConfigParser 11 | 12 | # Selects the environment to run the game on: simulator or real 13 | device = 'sim'; 14 | 15 | def run(program, type, shots = 100): 16 | if type == 'real': 17 | if not run.isInit: 18 | # Setup the API key for the real quantum computer. 19 | parser = RawConfigParser() 20 | parser.read('config.ini') 21 | IBMQ.enable_account(parser.get('IBM', 'key')) 22 | run.isInit = True 23 | 24 | # Set the backend server. 25 | backend = qiskit.providers.ibmq.least_busy(qiskit.IBMQ.backends(simulator=False)) 26 | 27 | # Execute the program on the quantum machine. 28 | print("Running on", backend.name()) 29 | job = qiskit.execute(program, backend) 30 | return job.result().get_counts() 31 | else: 32 | # Execute the program in the simulator. 33 | print("Running on the simulator.") 34 | job = qiskit.execute(program, qiskit.Aer.get_backend('qasm_simulator'), shots=shots) 35 | return job.result().get_counts() 36 | 37 | # Get the status for the current state of the unicorn. 38 | def status(altitude): 39 | if altitude == 0: 40 | return 'Your unicorn is waiting for you on the ground' 41 | elif altitude <= 100: 42 | return 'Your unicorn is floating gently above the ground' 43 | elif altitude <= 200: 44 | return 'Your unicorn is hovering just above the evergreen sea of trees' 45 | elif altitude <= 300: 46 | return 'Your unicorn is approaching the first misty cloud layer' 47 | elif altitude <= 400: 48 | return 'Your unicorn has soared through the misty pink clouds' 49 | elif altitude <= 500: 50 | return 'Your unicorn is well above the misty clouds' 51 | elif altitude <= 600: 52 | return 'You can barely see the evergreen sea of trees from this high up' 53 | elif altitude <= 700: 54 | return 'Your unicorn is soaring through the sky' 55 | elif altitude <= 800: 56 | return 'You can see the first glimpse of the golden castle gates just above you' 57 | elif altitude <= 900: 58 | return 'Your unicorn is nearly at the mystical castle gates' 59 | elif altitude < 1000: 60 | return 'Your unicorn swiftly glides through the mystical castle gate. You\'re almost there' 61 | else: 62 | return 'A roar emits from the crowd of excited sky elves, waiting to greet you' 63 | 64 | def action(command): 65 | command = command.lower()[0] 66 | 67 | switcher = { 68 | 'u': 150, 69 | 'd': -150, 70 | 'q': 0 71 | } 72 | 73 | return switcher.get(command, -1) 74 | 75 | run.isInit = False # Indicate that we need to initialize the IBM Q API in the run() method. 76 | isGameOver = False # Indicates when the game is complete. 77 | altitude = 0 # Current altitude of player. Once goal is reached, the game ends. 78 | goal = 1000 # Max altitude for the player to reach to end the game. 79 | shots = goal + (125 if device == 'real' else 0) # Number of measurements on the quantum machine; when shots == goal, the player reached the goal; we include a buffer on physical quantum computers to account for natural error. 80 | 81 | print('===============') 82 | print(' Fly Unicorn') 83 | print('===============') 84 | print('') 85 | print('Your majestic unicorn is ready for flight!') 86 | print('After a long night of preparation and celebration, it\'s time to visit the castle in the clouds.') 87 | print('Use your keyboard to fly up or down on a quantum computer, as you ascend your way into the castle.') 88 | print('') 89 | 90 | # Begin main game loop. 91 | while not isGameOver: 92 | # Setup a qubit to represent the unicorn. 93 | unicorn = QuantumRegister(1) 94 | unicornClassic = ClassicalRegister(1) 95 | program = QuantumCircuit(unicorn, unicornClassic); 96 | 97 | # Get input from the user. 98 | command = '' 99 | while not command.lower() in ['u', 'd', 'q', 'up', 'down', 'quit']: 100 | # Read input. 101 | command = input("\n=====================\n-[ Altitude " + str(altitude) + " feet ]-\n" + status(altitude) + ".\n[up,down,quit]: ").lower() 102 | 103 | # Process input. 104 | modifier = action(command) 105 | if modifier == 0: 106 | isGameOver = True 107 | elif modifier == -1: 108 | print("What?") 109 | else: 110 | if modifier > 0: 111 | print("You soar into the sky.") 112 | elif modifier < 0: 113 | if altitude > 0: 114 | print("You dive down lower.") 115 | else: 116 | print("Your unicorn can't fly into the ground!") 117 | 118 | # Calculate the amount of NOT to apply to the qubit, based on the percent of the new altitude from the goal. 119 | frac = (altitude + modifier) / goal 120 | if frac >= 1: 121 | # The unicorn is at or beyond the goal, so just invert the 0-qubit to a 1-qubit for 100% of goal. 122 | # Note: On a real quantum machine the error rate is likely to cause NOT(0) to not go all the way to 1, staying around 1=862 and 0=138, etc. 123 | program.x(unicorn) 124 | elif frac > 0: 125 | # Apply a percentage of the NOT operator to the unicorn (qubit), cooresponding to how high the unicorn is. 126 | program.u3(frac * math.pi, 0.0, 0.0, unicorn) 127 | 128 | # Collapse the qubit superposition by measuring it, forcing it to a value of 0 or 1. 129 | program.measure(unicorn, unicornClassic); 130 | 131 | # Execute on quantum machine. 132 | counts = run(program, device, shots) 133 | print(counts) 134 | 135 | # Set the altitude based upon the number of 1 counts in the quantum results. 136 | altitude = counts['1'] if '1' in counts else 0 137 | 138 | # Did the player reach the castle? 139 | if altitude >= goal: 140 | print('Congratulations! Your unicorn soars into the castle gates!') 141 | isGameOver = True 142 | --------------------------------------------------------------------------------