Last active
May 16, 2022 15:06
-
-
Save quantumjim/a5d885816f7dc042a78df11ce6cf9652 to your computer and use it in GitHub Desktop.
Gamified tutorial for QISKit to run on PythonAnywhere
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import math | |
def ClearScreen () : | |
# DESCRIPTION: | |
# Prints a whole bunch of space to screen | |
print("\n"*200) | |
def ColouredString (message,colour) : | |
# DESCRIPTION: | |
# Prints in a colour specified by the colour in ["r","b","p"] and then sets what follows back to white | |
# first the colour | |
coloured_message = "" | |
if colour=="r": # red | |
coloured_message += "\x1b[1;31m" | |
elif colour=="g": # green | |
coloured_message += "\x1b[1;32m" | |
elif colour=="b": # blue | |
coloured_message += "\x1b[1;34m" | |
elif colour=="p": # purple | |
coloured_message += "\x1b[1;35m" | |
else: # black (which should actually be the default text colour) | |
coloured_message += "\x1b[0m" | |
# then the message | |
coloured_message += message | |
# and back to black | |
coloured_message += "\x1b[0m" | |
return coloured_message | |
def Expect2Prob ( expect ) : | |
# DESCRIPTION: | |
# Converts expectation value to a probability of getting the outcome 1. | |
return (1-expect)/2 | |
def Expect2Polar ( boxes ) : | |
# DESCRIPTION: | |
# Takes the contents of an X and Z box and turns it into polar coordinates for the Bloch circle. | |
# INPUT: | |
# {String: Float} boxes Should have entries for "X" and "Z", which serve as the horizontal and vertical boxes respectively. | |
# OUTPUT: | |
# [Float] [ degrees, radius ] degrees is between 0 and 1. It is the angle clockwise from the top as a fraction of 2*Pi. Radius is how far out the point is. Will be 1 for pure states and 0 for maximally mixed. | |
radius = math.sqrt( boxes["X"]**2 + boxes["Z"]**2) | |
degrees = 0 # default value of 0 | |
if radius>0.0: | |
degrees = math.acos( -boxes["Z"] / radius ) / (2*math.pi) | |
if boxes["X"]>=0.0: | |
degrees = 1 - degrees | |
return [ degrees, radius ] | |
def Polar2Expect ( polar_coords ) : | |
# DESCRIPTION: | |
# As Boxes2Polar, but with inputs and outputs reversed | |
boxes = {} | |
boxes["X"] = -polar_coords[1] * math.sin( 2*math.pi*polar_coords[0]) | |
boxes["Z"] = -polar_coords[1] * math.cos( 2*math.pi*polar_coords[0]) | |
return boxes | |
def ExchangeBoxes ( state, box1, box2 ) : | |
# DESCRIPTION: | |
# Given a state and two of its boxes, the values for these boxes are exchanged | |
output_state = state | |
temp = output_state[box1] | |
output_state[box1] = output_state[box2] | |
output_state[box2] = temp | |
return output_state | |
def Swap ( state ) : | |
# DESCRIPTION: | |
# Determines the state after a swap gate | |
# INPUT: | |
# {String: Float} state Two qubit state. | |
# OUTPUT: | |
# {String: Float} state Transformed version of input state. | |
swapped_state = {} | |
for box in state.keys(): | |
swapped_state[box[1]+box[0]] = state[box] | |
return swapped_state | |
def ApplyGate ( state, gate, qubit ) : | |
# DESCRIPTION: | |
# Transforms the given state according to the given gate. | |
# INPUT: | |
# {String: Float} state Full two qubit state. Needs entries for XI, ZI, IZ, IX, XX, XZ, ZX, ZZ and YY | |
# String gate QISKit style str to specify a gate (can be x, z, h, q, qdg, or cz) | |
# Int qubit Qubit on which single qubit gate is applied. Unused for CZ. | |
# OUTPUT: | |
# {String: Float} state Transformed version of input state. | |
# We begin constructing the output state by copying the input state. | |
output_state = state | |
# Single qubit gates require special treatment, so we deal with these separately. | |
if gate in ["x","z","h","q","qdg"] : | |
# Single qubit gates act on pairs of boxes. These are the pairs that form Bloch circles. | |
# For qubit 0, these pairs are (XI, ZI), (XX,ZX) and (XZ,ZZ). | |
# For qubit 2 they are (IX, IZ), (XX,XZ) and (ZX,ZZ). | |
# Here we loop over and construct the three pairs, which in each case will be (p[0],p[1]). | |
for rc in ["I","X","Z"] : | |
box_name = {"X":rc,"Z":rc} | |
for p in ["X","Z"] : | |
if qubit=="0" : | |
box_name[p] = p + box_name[p] | |
else : | |
box_name[p] = box_name[p] + p | |
# What we do to the pairs depends on the gate we apply. | |
if gate=="x": # invert Z box and invert YY | |
output_state[box_name["Z"]] = -output_state[box_name["Z"]] | |
output_state["YY"] = -output_state["YY"] | |
elif gate=="z" :# invert X box and invert YY | |
output_state[box_name["X"]] = -output_state[box_name["X"]] | |
output_state["YY"] = -output_state["YY"] | |
elif gate=="h" : # exchange X and Z boxes and invert YY | |
output_state = ExchangeBoxes( output_state, box_name["X"], box_name["Z"]) | |
output_state["YY"] = -output_state["YY"] | |
elif gate in ["q","qdg"] : | |
polar_coords = Expect2Polar( { "X":output_state[box_name["X"]], "Z":output_state[box_name["Z"]] } ) # convert to polar coords | |
if gate=="q" : # change angle according to the rotation | |
polar_coords[0] += 1/8 | |
else : | |
polar_coords[0] -= 1/8 | |
# convert back to boxes | |
output_boxes = Polar2Expect(polar_coords) | |
for p in ["X","Z"] : | |
output_state[box_name[p]] = output_boxes[p] | |
else : | |
print("Error: Unknown single qubit gate") | |
# Now for the two qubit gates | |
elif gate=="cz" : | |
# exchange contents of XI and XZ | |
output_state = ExchangeBoxes( output_state, "XI", "XZ") | |
# exchange contents of IX and ZX | |
output_state = ExchangeBoxes( output_state, "IX", "ZX") | |
# exchange contents of XX and YY | |
output_state = ExchangeBoxes( output_state, "XX", "YY") | |
elif gate=="cx" : | |
if qubit=="1" : | |
# exchange contents of XI and XX | |
output_state = ExchangeBoxes( output_state, "XI", "XX") | |
# exchange contents of IZ and ZZ | |
output_state = ExchangeBoxes( output_state, "IZ", "ZZ") | |
# exchange contents of XZ and YY | |
output_state = ExchangeBoxes( output_state, "XZ", "YY") | |
# invert XZ | |
output_state["XZ"] = -output_state["XZ"] | |
elif qubit=="0" : | |
# exchange contents of ZI and ZZ | |
output_state = ExchangeBoxes( output_state, "ZI", "ZZ") | |
# exchange contents of IX and XX | |
output_state = ExchangeBoxes( output_state, "IX", "XX") | |
# exchange contents of ZX and YY | |
output_state = ExchangeBoxes( output_state, "ZX", "YY") | |
# invert ZX | |
output_state["ZX"] = -output_state["ZX"] | |
output_state["YY"] = -output_state["YY"] # invert YY | |
else : | |
print("Error: Unknown gate") | |
return output_state | |
def MakeState ( initial_state, gates ) : | |
# DESCRIPTION: | |
# Constructs a state given an initial state and list of gates | |
# Can also be used to construct an initial state such that the target state and solution are as specified by the input | |
# In this case, note that the inverse of the desired solution must be supplied | |
# Put simply, this means that the first gate should be on the right, and the substition q <-> qdg should be used | |
state = initial_state | |
for gate in gates : | |
state = ApplyGate( state, gate[0], gate[1] ) | |
return state | |
def MakeCell ( cell_state ) : | |
# DESCRIPTION: | |
# Prints a single box or Bloch circle, depending on the input state. | |
# INPUT: | |
# {String: Float} cell_state With key "X", value is the expectation value for horizontal red box. | |
# Similarly for "Z" and the vertical blue box, and "Y" for a diagonal purple box. | |
# Note that a cell that uses "Y" will correspond to XZ or ZZ boxes. Not a Y box. | |
# OUTPUT: | |
# [String] lines List of 12 lines, which when printed sequentially will display the cell. | |
# PROCESS: | |
# When a single key is supplied, the corresponding box is printed. | |
# When both "X" and "Z" are supplied, the boxes are combined into a Bloch circle. | |
# In all cases, the level on the box is first converted from the expectation value to the probability. | |
reso = {"X":17, "Z":9, "Y":13} # number of characters used for each type of box (including center) | |
bottom = "───────────────────────" # bottom border | |
right = "|" # right border | |
# The 8 points around the circle and one in the middle. Default to a dot | |
c = [] | |
c.append("˙") | |
c.append(".") | |
c.append("·") | |
c.append("˙") | |
c.append(".") | |
c.append("˙") | |
c.append("·") | |
c.append(".") | |
c.append(" ") | |
# When a Bloch sphere is displayed, the point corresponding to the state is denoted by "*" | |
# This is displayed only for pretty mixed states (radius <0.25) and pretty pure ones (radius>0.75) | |
if ( "X" in cell_state.keys() and "Z" in cell_state.keys() ) : # both X and Z boxes need to be present in the cell | |
if ( Expect2Polar( cell_state )[1]<0.25 ) : # if state is pretty mixed, point is shown in the center | |
c[8] = "*" | |
elif Expect2Polar( cell_state )[1]>0.75 : # if state is pretty pure, it is one of the 8 around the edge | |
point = 0 | |
degree = Expect2Polar( cell_state )[0] | |
for eighth in range(1,8) : | |
if degree>(float(eighth)/8 - 1.0/16) and degree<=(float(eighth)/8 + 1.0/16 ) : | |
point = eighth | |
if point in [1,4,7] : | |
c[ point ] = "⁎" | |
else : | |
c[ point ] = "*" | |
# Strings for the three boxes. Blank if unused, but filled with █ and ░ if used to represent how 'filled' they are. | |
b = {"X":[], "Z":[], "Y":[] } | |
for box in [ "X", "Z", "Y" ] : | |
this_b = [] | |
if box not in cell_state.keys() : | |
for _ in range(1,reso[box]+1) : | |
this_b.append(" ") | |
else : | |
prob = Expect2Prob( cell_state[box] ) # convert from expectation value to prob of a 1 outcome | |
fill = int( float(reso[box]) * prob ) | |
if (prob>0.5 and fill != reso[box]) : # if over half filled, but not completely filled, round up (for clear visuals) | |
fill += 1 | |
for _ in range(fill) : | |
if box == "X" : | |
this_b.append( ColouredString( "█" , "r" ) ) | |
elif box == "Z" : | |
this_b.append( ColouredString( "█" , "b" ) ) | |
elif box == "Y" : | |
this_b.append( ColouredString( "█" , "p" ) ) | |
for _ in range(fill,reso[box]) : | |
if box == "X" : | |
this_b.append( ColouredString( "░" , "r" ) ) | |
elif box == "Z" : | |
this_b.append( ColouredString( "░" , "b" ) ) | |
elif box == "Y" : | |
this_b.append( ColouredString( "░" , "p" ) ) | |
b[box] = this_b | |
# center is X with the colour of the cell, unless the cell is empty | |
if "Y" in cell_state.keys() : | |
c[8] = ColouredString( b["Y"][int(reso["Y"]/2)], "p" ) | |
elif "X" in cell_state.keys() : | |
c[8] = ColouredString( b["X"][int(reso["X"]/2)], "r" ) | |
elif "Z" in cell_state.keys() : | |
c[8] = ColouredString( b["Z"][int(reso["Z"]/2)], "b" ) | |
b["X"][int(reso["X"]/2)] = c[8] # The center will be the ninth element of c instead | |
# Declare and construct the lines. | |
lines = [] | |
if cell_state=={"II":1.0} : | |
for _ in range(11) : | |
lines.append( " "+right ) | |
else : | |
lines.append( " .· "+c[0]+" ·. "+right ) | |
lines.append( " "+c[7]+"˙ "+b["Z"][8]+" ˙"+c[1]+" "+right ) | |
lines.append( " · "+b["Z"][7]+" "+b["Y"][11]+b["Y"][12]+" · "+right ) | |
lines.append( " · "+b["Z"][6]+" "+b["Y"][9]+b["Y"][10]+" · "+right ) | |
lines.append( " "+b["Z"][5]+""+b["Y"][7]+b["Y"][8]+" "+right ) | |
lines.append( ""+c[6]+" "+"".join(b["X"])+" "+c[2]+" "+right ) | |
lines.append( " "+b["Y"][4]+b["Y"][5]+""+b["Z"][3]+" "+right ) | |
lines.append( " ˙ "+b["Y"][2]+b["Y"][3]+" "+b["Z"][2]+" ˙ "+right ) | |
lines.append( " · "+b["Y"][0]+b["Y"][1]+" "+b["Z"][1]+" · "+right ) | |
lines.append( " "+c[5]+". "+b["Z"][0]+" ."+c[3]+" "+right ) | |
lines.append( " ˙· "+c[4]+" ·˙ "+right ) | |
lines.append( bottom + right ) | |
return lines | |
def MakeGrid ( state, shown_qubit, active_qubit, bloch ) : | |
# DESCRIPTION: | |
# The inputs describe what the grid is doing. This function puts all that information together to actually make the grid. | |
# INPUT: | |
# {String: Float} state Full two qubit state. Needs entries for XI, ZI, IZ, IX, XX, XZ, ZX, ZZ and YY | |
# Int shown_qubit If this is 0 or 1, only the two boxes of that qubit are shown. Otherwise, all are shown. | |
# Int active_qubit If this is 0 or 1, the diagonals are straightened according to their function for this qubit. Otherwise they remain diagonal. | |
# Bool bloch Whether or not to display Bloch circles for the qubit specified above | |
# OUTPUT: | |
# [String] grid_lines An array of strs that represent the grid | |
cells = { "XI":[], "ZI":[], "XX":[],"XZ":[],"ZX":[],"ZZ":[],"YY":[],"II":[], "IX":[], "IZ":[] } | |
# determine which cells behave in which way (I is blank, B is Bloch circle, X and Z are horizontal and vertical boxes and Y are diagonal) | |
grid_lines = [] | |
cell_types = {} | |
if bloch : | |
if shown_qubit==0 : | |
cell_types = {"I":["II","ZI","XX","XZ","ZX","ZZ","YY","IX","IZ"],"X":[],"Y":[],"Z":[],"B":["XI"]} # shown_qubit is used as active qubit | |
elif shown_qubit==1 : | |
cell_types = {"I":["II","XI","ZI","XX","XZ","ZX","ZZ","YY","IZ"],"X":[],"Y":[],"Z":[],"B":["IX"]} # shown_qubit is used as active qubit | |
else : | |
if active_qubit==0 : | |
cell_types = {"I":["II","ZI","ZX","ZZ"],"X":["IX"],"Y":[],"Z":["IZ"],"B":["XI","XX","XZ"]} | |
elif active_qubit==1 : | |
cell_types = {"I":["II","IZ","XZ","ZZ"],"X":["XI"],"Y":[],"Z":["ZI"],"B":["IX","XX","ZX"]} # these are the same as above but with strs reversed | |
else : | |
print("Error: A valid qubit must be chosen to display a Bloch circle") | |
else : | |
if shown_qubit==0 : | |
cell_types = {"I":["II","XX","XZ","ZX","ZZ","YY","IX","IZ"],"X":["XI"],"Y":[],"Z":["ZI"],"B":[]} | |
elif shown_qubit==1 : | |
cell_types = {"I":["II","XI","ZI","XX","XZ","ZX","ZZ","YY","IX","IZ"],"X":["IX"],"Y":[],"Z":["IZ"],"B":[]} | |
else : | |
# Y for diagonal boxes, since there is no active qubit | |
cell_types = {"I":["II"],"X":["XI","IX","XX"],"Y":["XZ","ZX"],"Z":["ZI","IZ","ZZ"],"B":[]} | |
# make blank cell | |
for cell in cell_types["I"] : | |
if cell=="II" : | |
cells[cell] = MakeCell( {"II":1.0} ) | |
else : | |
cells[cell] = MakeCell( {} ) | |
# make cells with horizontal and vertical boxes | |
for cell_type in ["X","Z"] : | |
for cell in cell_types[cell_type] : | |
cells[cell] = MakeCell( { cell_type: state[cell] } ) | |
# make cells with diagonal boxes | |
for cell in cell_types["Y"] : | |
if active_qubit in [0,1] : | |
index = active_qubit | |
cells[cell] = MakeCell( { str(cell[index]):state[cell] } ) # qubit dependent cell type is used | |
else : | |
cells[cell] = MakeCell( { "Y":state[cell] } ) # same as in X,Z loop above | |
# make cells with Bloch circle | |
for cell in cell_types["B"] : | |
index = (1-active_qubit) | |
if active_qubit==0 : | |
cells[cell] = MakeCell( { "X":state["X"+str(cell[index])], "Z":state["Z"+str(cell[index])] } ) | |
else : | |
cells[cell] = MakeCell( { "X":state[str(cell[index])+"X"], "Z":state[str(cell[index])+"Z"] } ) | |
for l in range(12) : | |
grid_lines.append( cells["II"][l] + cells["ZI"][l] + cells["XI"][l] ) | |
for l in range(12) : | |
grid_lines.append( cells["IZ"][l] + cells["ZZ"][l] + cells["XZ"][l] ) | |
for l in range(12) : | |
grid_lines.append( cells["IX"][l] + cells["ZX"][l] + cells["XX"][l] ) | |
return grid_lines | |
def PrintScreen ( message, level, intro, program, state, shown_qubit, active_qubit, bloch, allowed_gates, required_gates ) : | |
print("\n"*3) | |
# set up the screen: job 1 | |
# text at the top | |
ClearScreen () | |
print("\nLevel "+str(level+1)+"\n") | |
for line in intro[level] : | |
print("> " + line + "...") | |
if program != [] : | |
print("\nYour QISKit program so far\n") | |
for line in program : | |
print(line) | |
print("\n") | |
# set up the screen: job 2 | |
# the grid | |
print("\n") | |
grid_lines = MakeGrid( state, shown_qubit, active_qubit, bloch ) | |
for line in grid_lines : | |
print(" "+line) | |
# set up the screen: job 3 | |
# state allowed gates | |
for qubit in allowed_gates.keys() : | |
gate_list = "" | |
for gate in allowed_gates[qubit].keys() : | |
if required_gates[qubit][gate] > 0 : | |
gate_list += " "+gate+" (use exactly "+str(required_gates[qubit][gate])+" times)" | |
elif allowed_gates[qubit][gate]==0: | |
gate_list += " "+gate | |
if gate_list!="" : | |
if qubit=="both" : | |
print("\nAllowed two qubit operations:") | |
else : | |
print("\nAllowed operations for qubit " + qubit + ":") | |
print(gate_list) | |
return input("\n"+message+"\n") | |
def WriteQISKit( gate, qubit, qubits_used, program, mode): | |
if mode=="5": | |
regL = "" | |
regR = "" | |
else: | |
regL = "qubit[" | |
regR = "]" | |
if gate=="cz" : | |
program.append("program.cz( "+regL+qubits_used[0]+regR+", "+regL+qubits_used[1]+regR+" )") | |
elif gate=="cx" : | |
if qubit==qubits_used[0] : | |
program.append("program.cx( "+regL+qubits_used[1]+regR+", "+regL+qubits_used[0]+" )") | |
else : | |
program.append("program.cx( "+regL+qubits_used[0]+regR+", "+regL+qubits_used[1]+" )") | |
elif gate in ["q","qdg"]: | |
sign = "-"*(gate=="qdg") | |
program.append("program.u3( "+sign+"math.pi/4,0,0, "+regL+qubit+regR+" )") | |
else : | |
program.append("program."+gate+"( "+regL+qubit+regR+" )") | |
def MakeTarget ( initial_state, gates ): | |
if gates=='swap': | |
target = Swap( initial_state ) | |
else: | |
target = MakeState( initial_state, gates ) | |
target_string = "\n" | |
for line in MakeGrid(target,2,2,False): | |
target_string += " " + line + "\n" | |
return target, target_string |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# Created by James Wootton | |
# Copyright © 2018 University of Basel. All rights reserved. | |
from Engine import * | |
# Story Mode | |
def GetLevelStory ( ) : | |
state_list = [] | |
success_condition_list = [] | |
qubits_used_list = [] | |
allowed_gates_list = [] | |
intro = [] | |
outro = [] | |
#1 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":3}, "1":{}, "both":{} } ) | |
intro.append( ["In these puzzles, you'll see a grid and be given a task", | |
"Your job is to complete that task by using quantum programming", | |
"Your first job concerns a single qubit, which we call qubit 0", | |
"The state of this is visualized on the grid using two coloured boxes", | |
"Each is either on, off, or something in between", | |
"In the first puzzle, your job is to turn the blue box off using the command known as x", | |
"One x should be enough but, to make sure it's working properly, do it three times instead", | |
"TARGET: Turn off the blue box, and use the x command 3 times"] ) | |
outro.append( ["Great!", | |
"The x command turns the blue box on and off, and does nothing to the red box"] ) | |
#2 | |
state_list.append( {"XI":0.0, "ZI":0.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{}, "1":{"x":3}, "both":{} } ) | |
intro.append( ["Now we'll look at another qubit, called qubit 1", | |
"It's also described by two boxes. But because it's a different qubit, they are in a different place", | |
"To reset it, and to test out the x, do the same as before", | |
"TARGET: Turn off the blue box, and use the x command 3 times"] ) | |
outro.append( ["Great!", | |
"Now you've gotten the hang of x, you won't need to repeat it 3 times any more."] ) | |
#3 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0}, "1":{}, "both":{} } ) | |
intro.append( ["Now we move on to another chip, with another qubit 0. But what is a qubit?", | |
"A qubit is a quantum object that can be turned into a bit", | |
"There are many ways we can do this, and the result we get depends on the method we use", | |
"The two boxes represent our two favourite methods of extracting a bit", | |
"We usually use the blue box: If it's 'off', we get 0; if it's 'on' we get 1", | |
"TARGET: Turn off the blue box"] ) | |
outro.append( ["Great!","You can also learn about how we visualze the qubits at\n https://medium.com/qiskitters/visualizing-bits-and-qubits-9af287047b28 ","Now for the next qubit"] ) | |
#4 | |
state_list.append( {"XI":0.0, "ZI":0.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{}, "1":{"x":0}, "both":{} } ) | |
intro.append( ["Looks like this will just be another blue box to turn off", | |
"TARGET: Turn off the blue box"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#5 | |
state_list.append( {"XI":1.0, "ZI":0.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"h":3}, "1":{}, "both":{} } ) | |
intro.append( ["This chip has a new operation enabled, called h", | |
"It swaps the contents of the two boxes", | |
"To test it out, do the old trick of repeating three times", | |
"TARGET: Turn off the blue box, and use the h command 3 times"] ) | |
outro.append( ["Great!", | |
"Now for the next qubit"] ) | |
#6 | |
state_list.append( {"XI":0.0, "ZI":0.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":1.0, "IZ":0.0} ) | |
success_condition_list.append( {"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{}, "1":{"x":3,"h":0}, "both":{} } ) | |
intro.append( ["Have you noticed that x has no effect when the blue box is only half on?", | |
"It inverts what the box is doing: off becomes on, on becomes off, but half remains half", | |
"TARGET: Turn off the blue box, and use the x command 3 times"] ) | |
outro.append( ["Great!", | |
"By the way, extracting an output from a box that's half on would give a random result"] ) | |
#7 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"z":0,"h":0}, "1":{}, "both":{} } ) | |
intro.append( ["The x operation isn't working on this chip", | |
"But you will have a new operation, called z, which inverts the red box instead", | |
"You'll need work out how to reset the qubits with z and h", | |
"TARGET: Turn off the blue box without using the x command"] ) | |
outro.append( ["Great!","Now for the next qubit"] ) | |
#8 | |
state_list.append( {"XI":0.0, "ZI":0.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":1.0, "IZ":0.0} ) | |
success_condition_list.append( {"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{}, "1":{"z":0,"h":0}, "both":{} } ) | |
intro.append( ["The red boxes represent another way to get a bit out of a qubit", | |
"Again, 'off' gives you a 0 and 'on' gives you a 1." | |
"The red box can only be certain of the result it would give when the blue box is completely random", | |
"Qubits only have a limited amount of certainty to go round", | |
"The h command swaps the results you'd get for blue and red", | |
"TARGET: Move the off to blue and the randomness to red"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#9 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":1.0,"ZZ":0.0,"YY":0.0, | |
"IX":-1.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{} } ) | |
intro.append( ["Now you know the basic tools, you can tackle both qubits at once", | |
"You'll see the four boxes you are used to, which represent the two qubits", | |
"There will be some extra ones too, but don't worry about these for now", | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#10 | |
state_list.append( {"XI":-1.0, "ZI":0.0, | |
"XX":0.0,"XZ":1.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"z":0,"h":0}, "1":{"z":0,"h":0}, "both":{} } ) | |
intro.append( ["Another chip with the x turned off", | |
"So another chance to practice your workarounds", | |
"TARGET: Turn off the blue boxes without using the x command"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#11 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{} } ) | |
intro.append( ["In case you are wondering about the extra boxes, they tell us about the relationship between the two qubits", | |
"The blue one, for example, keeps track of how likely the two blue outputs are to agree", | |
"It is off when the blue ouptuts of the two qubits will definitely agree, and on when they'll definitely disagree", | |
"Keep an eye on how it changes on this chip", | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!", | |
"The extra red box similarly looks for agreements of the red boxes", | |
"The two purple ones are for the blue output of one qubit, and the red one of the other"] ) | |
#12 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":1.0,"ZZ":0.0,"YY":0.0, | |
"IX":-1.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{} } ) | |
intro.append( ["The x doesn't just invert the blue box of qubit 0, but all the boxes in that column", | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#13 | |
state_list.append( {"XI":-1.0, "ZI":0.0, | |
"XX":0.0,"XZ":1.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"z":0,"h":0}, "1":{"z":0,"h":0}, "both":{} } ) | |
intro.append( ["The z for qubit 0 similarly affects all the boxes of the other column", | |
"TARGET: Turn off the blue boxes without using the x command"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#14 | |
state_list.append( {"XI":-1.0, "ZI":0.0, | |
"XX":0.0,"XZ":1.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"z":0,"h":0}, "1":{"z":0,"h":0}, "both":{} } ) | |
intro.append( ["The h for qubit 0 swaps the two columns", | |
"TARGET: Turn off the blue boxes without using the x command"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#15 | |
state_list.append( {"XI":1.0, "ZI":-1.0, | |
"XX":1.0,"XZ":0.0,"ZX":1.0,"ZZ":0.0,"YY":0.0, | |
"IX":-1.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{} } ) | |
intro.append( ["The operations for qubit 1 have similar effects, but on the rows instead of the columns", | |
"The x affects one row, z affects the other, and h swaps them", | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#16 | |
state_list.append( {"XI":-1.0, "ZI":0.0, | |
"XX":1.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":-1.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{} } ) | |
intro.append( ["This is a nice chip with everything working. So just do your magic!", | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!","Now on to the next chip", | |
"Have you noticed the program that is getting displayed as you work", | |
"This is the code you are writing for the quantum computer, using the QISKit SDK", | |
"Check out qiskit.org for more information"] ) | |
#17 | |
state_list.append( {"XI":1.0, "ZI":-1.0, | |
"XX":1.0,"XZ":0.0,"ZX":1.0,"ZZ":0.0,"YY":0.0, | |
"IX":-1.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{} } ) | |
intro.append( ["Another well behaved chip", | |
"By the way, most of IBM's chips have more than just two qubits", | |
"In fact, you can use a real device with 16 qubits from the comfort of your own home" | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#18 | |
state_list.append( {"XI":0.0, "ZI":0.0, | |
"XX":0.0,"XZ":1.0,"ZX":1.0,"ZZ":0.0,"YY":1.0, | |
"IX":0.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{"cz":0} } ) | |
intro.append( ["This chip has a new operation enabled: cz", | |
"Like h, we can think of this as swapping the contents of boxes", | |
"It swaps the contents of the red box of each qubit with the purple box next to it", | |
"These swaps let us make big changes to the way the qubits are correlated with each other", | |
"For this reason, cz is known as an entangling operation", | |
"You'll probably need to use it to disentangle the qubits here", | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!", | |
"This box swapping interpretation is just one way to understand the cz", | |
"On the next chip, you'll need to use another"] ) | |
#19 | |
state_list.append( {"XI":0.0, "ZI":1.0, | |
"XX":0.0,"XZ":0.0,"ZX":-1.0,"ZZ":0.0,"YY":0.0, | |
"IX":-1.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["The cz can also be thought of as a conditional operation", | |
"If the blue box for qubit 0 is off, the cz does nothing", | |
"But if it is on, the cz does a z on qubit 1", | |
"Since the normal z is not working for on this chip, and x only works for qubit 0, this feature of the cz should come in handy", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#20 | |
state_list.append( {"XI":0.0, "ZI":0.0, | |
"XX":1.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":-1.0, | |
"IX":0.0, "IZ":0.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{"cz":0} } ) | |
intro.append( ["This chip is in an entangled state. The qubits are correlated in a way that only quantum objects can be", | |
"Though outputs coming from both qubits will be completely random, and have not yet decided what to randomly be, they are certain to always agree", | |
"What does this mean for the cz? If the blue boxes are full of undecided randomness, does a z get applied to qubit 1 or not?", | |
"For the time being, you are probably better off with the box swapping interpretation when stuff like this is going on", | |
"TARGET: Turn off the blue boxes"] ) | |
outro.append( ["Great!", | |
"Now on to the next chip, and another interpretation of the cz"] ) | |
#21 | |
state_list.append( {"XI":-1.0, "ZI":0.0, | |
"XX":0.0,"XZ":-1.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( {"ZI":1.0,"IZ":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0},"1":{"x":0,"h":0}, "both":{"cz":0} } ) | |
intro.append( ["You have used cz to do something to qubit 1 that was condition on qubit 0", | |
"Sometimes you might want an operation that works the other way", | |
"It turns out that cz does this too! The exact same operation can be interpreted in the opposite way", | |
"Which is handy, since it is qubit 0 for which x and z aren't working for this chip", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great! The fact that all three of these interpretations of cz are true at once is quite an interesting feature", | |
"There are those who like to reflect upon the mystery of how this works", | |
"But they aren't tiny, and stuck in a fancy fridge and trying to do a job that they can't even remember", | |
"So you'd better save your reflections for later. On to the next chip!"] ) | |
#22 | |
state_list.append( {"XI":0.0, "ZI":1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":-1.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["Combining the cz with other operations, we can get new kinds of conditional behaviour", | |
"For example, what if we wanted a conditional x rather than a conditional z", | |
"Using your expertise with using a z to make an x, you should be able to work it out", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!", | |
"You made an operation that does an x on qubit 1, depending on whether the blue box of qubit 0 is on", | |
"We call this the cx operation, or the cnot"] ) | |
#23 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":-1.0,"YY":0.0, | |
"IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"x":0,"z":0,"h":0}, "both":{"cz":0} } ) | |
intro.append( ["Unlike cz, the cx operation is not symmetric", | |
"To make it conditional on qubit 1 instead, you'll need to apply h elsewhere", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#24 | |
state_list.append( {"XI":0.0, "ZI":1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":-1.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0}, "1":{"h":0,"cx":0}, "both":{} } ) | |
intro.append( ["Most IBM quantum devices actually use cx as the basic entangling operation instead of cz", | |
"Which means you have to worry about which way round you are allowed to apply them", | |
"This chip is one of those devices", | |
"You have a cx that is conditional on the blue box of qubit 0, and which can apply an x to qubit 1", | |
"Though it affects both qubits, you'll find it in your list of allowed operations for qubit 1", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#25 | |
state_list.append( {"XI":-1.0, "ZI":0.0, | |
"XX":-1.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, | |
"IX":1.0, "IZ":0.0} ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0,"z":0,"cx":0}, "both":{} } ) | |
intro.append( ["Like the cz, there are different ways to interpret the cx", | |
"In the last chip we used the fact that it does an x to qubit 1 conditional on the blue box of qubit 0", | |
"But it can also be interpreted as doing a z to qubit 0, conditional on the red box of qubit 1", | |
"This is the interpretation you'll need to reset this chip", | |
"But since everyone is so obsessed with the other interpretation, you'll still find it in your list of allowed qubit 1 operations", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!","Now on to the next chip"] ) | |
#26 | |
state_list.append( {"XI":0.0, "ZI":-1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0, | |
"IX":0.0, "IZ":-1.0} ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0,"x":0,"cx":0}, "1":{"h":0}, "both":{} } ) | |
intro.append( ["The cx on this chip is the other way around: It does an x to qubit 0 conditional on the blue box of qubit 1", | |
"Unfortunately, one that does the x to qubit 1 is what you need to reset this chip", | |
"But don't worry. With a few h operations you can turn the cx around", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!", | |
"With an h on both qubits before and after a cx, it effectively works the other way around", | |
"If you remember anything from your time here, it should be this", | |
"It is a very useful trick when using IBM's cx based devices", | |
"Now on to the next chip"] ) | |
#27 | |
state_list.append( MakeState( {"XI":0, "ZI":1,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, [["qdg","0"],["qdg","0"],["qdg","0"]]) ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"bloch":1,"q":0}, "1":{}, "both":{"unbloch":0} } ) | |
intro.append( ["This chip is used to test an operation called u3(math.pi,0,0)", | |
"But that's a lot to type, so we'll call it q instead", | |
"To introduce the q gate, we'll go back to doing the qubits one-by-one", | |
"The q operation makes most sense when the qubits boxes are drawn on top of each other", | |
"To do this, use the bloch command", | |
"TARGET: Use the bloch command on qubit 0, and turn off the blue boxes using the q gate"] ) | |
outro.append( ["Great!", "On to the next qubit"] ) | |
#28 | |
state_list.append( MakeState( {"XI":0, "ZI":1,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, [["qdg","1"],["qdg","1"],["qdg","1"]]) ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{}, "1":{"bloch":1,"q":0}, "both":{"unbloch":0} } ) | |
intro.append( ["So what does this q thing do?", | |
"Around the boxes, are a circle", | |
"In this circle, at the point where the levels of the boxes meet, is a *", | |
"The job of the q operation is to rotate that point, dragging the levels of the boxes with it", | |
"One q rotates the point 1/8 of the way around the circle in the clockwise direction", | |
"TARGET: Use the bloch command on qubit 1, and turn off the blue boxes using the q gate"] ) | |
outro.append( ["Great!", "On to the next qubit"] ) | |
#29 | |
state_list.append( MakeState( {"XI":0, "ZI":1,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, | |
[["qdg","0"],["qdg","0"],["qdg","1"]]) ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"bloch":0,"q":0}, "1":{"bloch":0,"q":0}, "both":{"unbloch":0} } ) | |
intro.append( ["Now you can do both qubits at once", | |
"Notice that q on qubit 0 affects the columns, just like other qubit 0 operations", | |
"And q on qubit 1 affects the rows", | |
"You don't need to use the bloch operations for the qubits to apply q", | |
"But I'd advise that you do", | |
"TARGET: Turn off the blue boxes using the q gate"] ) | |
outro.append( ["Great!", "On to the next chip"] ) | |
#30 | |
state_list.append( MakeState( {"XI":0, "ZI":1,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, | |
[["qdg","0"],["q","1"]]) ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0,"bloch":0,"q":1}, "1":{"x":0,"z":0,"h":0,"bloch":0,"q":1}, "both":{"unbloch":0} } ) | |
intro.append( ["This chip will only let you do one q on each qubit", | |
"So hopefully you won't need more than that", | |
"If you do, you might be able to hack a solution using other operations", | |
"TARGET: Turn off the blue boxes using only one q gate on each qubit"] ) | |
outro.append( ["Great!", "On to the next chip"] ) | |
#31 | |
state_list.append( MakeState( {"XI":0, "ZI":1,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, | |
[["q","0"],["q","0"],["q","1"]]) ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0,"bloch":0,"q":0,"qdg":0}, "1":{"x":0,"z":0,"h":0,"bloch":0,"q":0,"qdg":0}, "both":{"unbloch":0} } ) | |
intro.append( ["A shortcut way of doing this hack is qdg", | |
"This is simply a anti-clockwise version of q", | |
"Or counter clockwise, if you prefer", | |
"Or widdershins. Widdershins is a great word. Let's all use widdershins", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!", "On to the next chip"] ) | |
#32 | |
state_list.append( MakeState( {"XI":0, "ZI":1,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, | |
[["z","0"],["h","0"],["h","1"]]) ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"bloch":0,"q":0,"qdg":0}, "1":{"x":0,"z":0,"bloch":0,"q":0,"qdg":0}, "both":{"unbloch":0} } ) | |
intro.append( ["The h operation is not working on this chip", | |
"Fortunately, you can build it using q or qdg", | |
"Use them to remind this chip how h is supposed to be done", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!", "On to the next chip"] ) | |
#33 | |
state_list.append( MakeState( {"XI":0, "ZI":1,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, | |
[["h","1"]]) ) | |
success_condition_list.append( {"IZ":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0,"bloch":0,"q":0,"qdg":0}, "1":{"x":0,"z":0,"bloch":0,"q":1,"qdg":1}, "both":{"unbloch":0,"cz":0} } ) | |
intro.append( ["With q and qdg, we can make conditional operations that are more interesting than just cz and cx", | |
"Like a one that does an h to one qubit, conditional on the other", | |
"Qubit 1 on this chip has a bunch of broken gates", | |
"So you may need to create one of these", | |
"TARGET: Turn off the blue boxes using the allowed gates"] ) | |
outro.append( ["Great!", | |
"You have successfully tested and reset a whole bunch of qubits", | |
"To find out how to do more than just reset them, check out the other modes in this program"] ) | |
level_num = len(state_list) | |
return state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro | |
# sandbox | |
def GetLevelSwaps () : | |
state_list = [] | |
success_condition_list = [] | |
qubits_used_list = [] | |
allowed_gates_list = [] | |
intro = [] | |
outro = [] | |
# 1 | |
state_list.append( {"XI":0.5, "ZI":0.5, | |
"XX":-0.5,"XZ":0.0,"ZX":0.0,"ZZ":-0.5,"YY":0.0, | |
"IX":-0.5, "IZ":-0.5} ) | |
target, target_string = MakeTarget( state_list[-1], 'swap' ) | |
success_condition_list.append( target ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["In these puzzles, your job is to swap the states of two qubits", | |
"This can always be done with nothing more than h operations, and either cz or cx", | |
"TARGET: Everything from qubit 0 must be moved to the same place on qubit 1, and vice-versa", | |
"So given the initial state you'll get, the final state should look like this", | |
target_string, | |
"Once the actual puzzle grid comes, you'll have to scroll up to see this again"] ) | |
outro.append( ["Well done!","Now try another"] ) | |
# 2 | |
state_list.append( {"XI":0.5, "ZI":0.0, | |
"XX":0.5,"XZ":0.5,"ZX":0.0,"ZZ":-0.5,"YY":0.5, | |
"IX":0.0, "IZ":0.5} ) | |
target, target_string = MakeTarget( state_list[-1], 'swap' ) | |
success_condition_list.append( target ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["TARGET: Everything from qubit 0 must be moved to the same place on qubit 1, and vice-versa", | |
"So given the initial state you'll get, the final state should look like this", | |
target_string, | |
"Once the actual puzzle grid comes, you'll have to scroll up to see this again"] ) | |
outro.append( ["Well done!","Now try another"] ) | |
# 3 | |
state_list.append( {"XI":0.0, "ZI":0.5, | |
"XX":-0.5,"XZ":0.0,"ZX":-0.5,"ZZ":0.5,"YY":0.5, | |
"IX":-0.5, "IZ":0.0} ) | |
target, target_string = MakeTarget( state_list[-1], 'swap' ) | |
success_condition_list.append( target ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["TARGET: Everything from qubit 0 must be moved to the same place on qubit 1, and vice-versa", | |
"So given the initial state you'll get, the final state should look like this", | |
target_string, | |
"Once the actual puzzle grid comes, you'll have to scroll up to see this again"] ) | |
outro.append( ["Well done!","Now try another"] ) | |
# 4 | |
state_list.append( {"XI":0.0, "ZI":-0.5, | |
"XX":0.0,"XZ":0.5,"ZX":0.5,"ZZ":-0.5,"YY":0.5, | |
"IX":0.0, "IZ":0.5} ) | |
target, target_string = MakeTarget( state_list[-1], 'swap' ) | |
success_condition_list.append( target ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["TARGET: Everything from qubit 0 must be moved to the same place on qubit 1, and vice-versa", | |
"So given the initial state you'll get, the final state should look like this", | |
target_string, | |
"Once the actual puzzle grid comes, you'll have to scroll up to see this again"]) | |
outro.append( ["Well done!","Now try another"] ) | |
# 5 | |
state_list.append( {"XI":0.0, "ZI":0.5, | |
"XX":0.0,"XZ":0.5,"ZX":-0.5,"ZZ":0.5,"YY":-0.5, | |
"IX":0.0, "IZ":0.5} ) | |
target, target_string = MakeTarget( state_list[-1], 'swap' ) | |
success_condition_list.append( target ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["TARGET: Everything from qubit 0 must be moved to the same place on qubit 1, and vice-versa", | |
"So given the initial state you'll get, the final state should look like this", | |
target_string, | |
"Once the actual puzzle grid comes, you'll have to scroll up to see this again"] ) | |
outro.append( ["Well done!","Now try another"] ) | |
# 6 | |
state_list.append( {"XI":0.5, "ZI":0.0, | |
"XX":-0.5,"XZ":-0.5,"ZX":-0.5,"ZZ":0.0,"YY":0.5, | |
"IX":-0.5, "IZ":0.0} ) | |
target, target_string = MakeTarget( state_list[-1], 'swap' ) | |
success_condition_list.append( target ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["TARGET: Everything from qubit 0 must be moved to the same place on qubit 1, and vice-versa", | |
"So given the initial state you'll get, the final state should look like this", | |
target_string, | |
"Once the actual puzzle grid comes, you'll have to scroll up to see this again"] ) | |
outro.append( ["Well done!","Now try another"] ) | |
# 7 | |
state_list.append( {"XI":0.5, "ZI":0.0, | |
"XX":0.5,"XZ":0.5,"ZX":-0.5,"ZZ":0.0,"YY":-0.5, | |
"IX":0.5, "IZ":0.0} ) | |
target, target_string = MakeTarget( state_list[-1], 'swap' ) | |
success_condition_list.append( target ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"h":0}, "1":{"h":0}, "both":{"cz":0} } ) | |
intro.append( ["TARGET: Everything from qubit 0 must be moved to the same place on qubit 1, and vice-versa", | |
"So given the initial state you'll get, the final state should look like this", | |
target_string, | |
"Once the actual puzzle grid comes, you'll have to scroll up to see this again"] ) | |
outro.append( ["Well done!", | |
"Your solution to each of these probably would have worked for all the others too", | |
"If so, you suceeded in making a swap gate!"] ) | |
level_num = len(state_list) | |
return state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro | |
# sandbox | |
def GetLevelSandbox () : | |
state_list = [] | |
success_condition_list = [] | |
qubits_used_list = [] | |
allowed_gates_list = [] | |
intro = [] | |
outro = [] | |
state_list.append( {"XI":0.0, "ZI":1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0, | |
"IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( {"XI":1.0,"ZI":1.0} ) | |
qubits_used_list.append( [ "0", "1" ] ) | |
allowed_gates_list.append( { "0":{"x":0,"z":0,"h":0,"bloch":0,"q":0,"qdg":0,"cx":0}, "1":{"x":0,"z":0,"h":0,"bloch":0,"q":0,"qdg":0,"cx":0}, "both":{"unbloch":0,"cz":0} } ) | |
intro.append( ["This is a sandox. You have all gates available, and can do what you want", | |
"The initial state is the one with ouput 00, which is the usual initial state for quantum computers", | |
"There are no conditions for success. You can just keep playing as long as you like", | |
"Bear in mind that ascii art isn't the most precise way of representing quantum states. So things might start looking strange for complex programs"] ) | |
outro.append( ["If you are seeing this, you somehow disproved Heisenberg's uncertainty principle", | |
"Either that or there is a bug"] ) | |
level_num = len(state_list) | |
return state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro | |
# image superposer | |
def GetLevelSuperposer ( string1, string2 ) : | |
state_list = [] | |
success_condition_list = [] | |
qubits_used_list = [] | |
allowed_gates_list = [] | |
intro = [] | |
outro = [] | |
definite = {"0":[],"1":[]} | |
superpos = {"same":[],"diff":[]} | |
first_super = -1 | |
for j in range(4) : | |
if string1[j]==string2[j] : | |
definite[str(string1[j])].append( str(j) ) | |
else : | |
if first_super == -1 : | |
first_super = j | |
superpos["same"].append( str(j) ) | |
else : | |
if string1[j]==string1[first_super] : | |
superpos["same"].append( str(j) ) | |
else : | |
superpos["diff"].append( str(j) ) | |
# if a bit is 0 in both file names, nothing need be done | |
# if a bit is 1 in both, this needs done | |
for j in definite["1"] : | |
state_list.append( {"XI":0.0, "ZI":1.0, | |
"XX":0.0,"XZ":0.0,"ZX":-1.0,"ZZ":0.0,"YY":0.0, | |
"IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( {"IZ":-1.0,} ) | |
qubits_used_list.append( [ "a", "b[" + j + "]" ] ) | |
allowed_gates_list.append( { "a":{}, "b[" + j + "]":{"x":0,"z":0,"h":0}, "both":{} } ) | |
intro.append( ["Since bit "+j+" has the value 1 for both in both file names, the qubit named b["+j+"] should be given a full blue box"] ) | |
outro.append( ["Great!", "Copy the QISKit program into the notebook."] ) | |
if first_super != -1 : | |
state_list.append( {"XI":0.0, "ZI":1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0, | |
"IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( {"XI":1.0} ) | |
qubits_used_list.append( [ "a", "b[0}" ] ) | |
allowed_gates_list.append( { "a":{"x":0,"z":0,"h":0}, "b[0}":{}, "both":{} } ) | |
intro.append( ["Since we are making a superposition of two things, so let's start with a superposition of 0 and 1 on a single qubit", | |
"We'll do it on qubit a, even though this won't actually be part of our final results", | |
"The superposition can be spread to the other qubits from here", | |
"Since we want a superposition of 0 and 1, we need a half full blue box", | |
"Let's go for the superposition for which the red box is empty"] ) | |
outro.append( ["Great!", | |
"Copy the QISKit program into the notebook."] ) | |
for j in superpos["same"] : | |
if j==str(first_super) : | |
state_list.append( {"XI":1.0, "ZI":0.0, "XX":0.0,"XZ":1.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, "IX":0.0, "IZ":1.0} ) | |
else : | |
state_list.append( {"XI":0.0, "ZI":0.0, "XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0, "IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( {"ZZ":1.0} ) | |
qubits_used_list.append( [ "a", "b[" + j + "]" ] ) | |
allowed_gates_list.append( { "a":{"z":0}, "b[" + j + "]":{"x":0,"z":0,"h":0}, "both":{"cz":0} } ) | |
intro.append( ["Since bit "+j+" has different values for the two file names, it needs to be part of the superposition", | |
"So we spread the superposition from qubit a to qubit b["+j+"] by copying the superposed bit", | |
"This will mean that both qubits will have random outputs from their blue boxes, but those outputs will always agree", | |
"The signature of this is that the middle blue box will be empty, so work towards this target"] ) | |
outro.append( ["Great!", | |
"Copy the QISKit program into the notebook."] ) | |
for j in superpos["diff"] : | |
state_list.append( {"XI":0.0, "ZI":0.0,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":0.0,"YY":0.0,"IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( {"ZZ":-1.0} ) | |
qubits_used_list.append( [ "a", "b[" + j + "]" ] ) | |
allowed_gates_list.append( { "a":{"z":0}, "b[" + j + "]":{"x":0,"z":0,"h":0}, "both":{"cz":0} } ) | |
intro.append( ["Since bit "+j+" has different values for the two file names, it needs to be part of the superposition", | |
"But since its value is always different to the first bit in the superposition, we also need to make it disagree", | |
"This means that the middle blue box will need to be full"] ) | |
outro.append( ["Great!", | |
"Copy the QISKit program into the notebook."] ) | |
level_num = len(state_list) | |
return state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro | |
# sandbox | |
def GetLevelBell () : | |
state_list = [] | |
success_condition_list = [] | |
qubits_used_list = [] | |
allowed_gates_list = [] | |
intro = [] | |
outro = [] | |
# create target state and string | |
target, target_string = MakeTarget( {"XI":0, "ZI":1.0,"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0,"IX":0.0, "IZ":1.0}, [["h","0"],["cx","1"],["q","0"],["h","0"]] ) | |
# add them in | |
state_list.append( {"XI":0.0, "ZI":1.0, | |
"XX":0.0,"XZ":0.0,"ZX":0.0,"ZZ":1.0,"YY":0.0, | |
"IX":0.0, "IZ":1.0} ) | |
success_condition_list.append( target ) | |
allowed_gates_list.append( { "A":{"x":0,"z":0,"h":0,"bloch":0,"q":0,"qdg":0,"cx":0}, "B":{"x":0,"z":0,"h":0,"bloch":0,"q":0,"qdg":0,"cx":0}, "both":{"unbloch":0,"cz":0} } ) | |
intro.append( ["This mode relates to a Jupyter notebook in which you can explore Bell tests", | |
"You'll find the notebook at https://github.com/decodoku/Quantum_Programming_Tutorial/tree/master/bell-test", | |
"A good state to aim for is the following", | |
target_string, | |
"But you can also use this mode as a sandbox and make whatever you like"]) | |
qubits_used_list.append( [ "A", "B" ] ) | |
outro.append( ["Great!", | |
"Copy the QISKit program into the quantum setup_variables() function in the bell_test notebook."] ) | |
level_num = len(state_list) | |
return state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
# Created by James Wootton | |
# Copyright © 2018 University of Basel. All rights reserved. | |
# import things we need | |
import math, copy | |
from Engine import * | |
from Levels import * | |
# clear screen and put title | |
ClearScreen () | |
print("") | |
print("") | |
print(" ██╗ ██╗███████╗██╗ ██╗ ██████╗ ") | |
print(" ██║ ██║██╔════╝██║ ██║ ██╔═══██╗ ") | |
print(" ███████║█████╗ ██║ ██║ ██║ ██║ ") | |
print(" ██╔══██║██╔══╝ ██║ ██║ ██║ ██║ ") | |
print(" ██║ ██║███████╗███████╗███████╗╚██████╔╝ ") | |
print(" ╚═╝ ╚═╝╚══════╝╚══════╝╚══════╝ ╚═════╝ ") | |
print(" ") | |
print(" ██████╗ ██╗ ██╗ █████╗ ███╗ ██╗████████╗██╗ ██╗███╗ ███╗") | |
print(" ██╔═══██╗██║ ██║██╔══██╗████╗ ██║╚══██╔══╝██║ ██║████╗ ████║") | |
print(" ██║ ██║██║ ██║███████║██╔██╗ ██║ ██║ ██║ ██║██╔████╔██║") | |
print(" ██║▄▄ ██║██║ ██║██╔══██║██║╚██╗██║ ██║ ██║ ██║██║╚██╔╝██║") | |
print(" ╚██████╔╝╚██████╔╝██║ ██║██║ ╚████║ ██║ ╚██████╔╝██║ ╚═╝ ██║") | |
print(" ╚══▀▀═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝") | |
print("\n") | |
print("\n") | |
print(" A GAMIFIED TUTORIAL FOR QUANTUM PROGRAMMING") | |
print(" ") | |
print(" For more information visit:") | |
print(" github.com/decodoku/Quantum_Programming_Tutorial") | |
print("\n") | |
print("\n") | |
print("\n") | |
print("\n") | |
print("\n") | |
print("\n") | |
input("> Note: For the best experience, you may need to zoom out\n> Press Enter to continue...\n") | |
ClearScreen() | |
print(" Choose which mode you want to play from the following list") | |
print("") | |
print(" 1 - Main Tutorial\n A gamified tutorial for programming quantum computers.\n") | |
print(" 2 - Qubit Swapper\n A few puzzles dedicated to the task of swapping qubits\n") | |
print(" 3 - Sandbox\n A chance to do what you want with two qubits.\n") | |
print(" 4 - Image Superposer\n Write a quantum program to create superpositions of images.\n") | |
print(" 5 - Bell Test\n Write a quantum program to explore the unique nature of quantum variables.\n") | |
choosing = True | |
while choosing: | |
mode = input("> Input a number to select a mode...\n") | |
if mode in ["1","2","3","4","5"]: | |
choosing = False | |
else: | |
input("> That's not a valid mode. Press Enter to try again...\n") | |
if mode in ["1","2"]: | |
if mode=="1": | |
state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelStory() | |
elif mode=="2": | |
state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelSwaps() | |
choosing = True | |
while choosing: | |
level = input("\n> Select a level (from 1 to "+str(level_num)+")...\n") | |
if level.isdigit(): | |
level = int(level) | |
if level in range(1,level_num+1): | |
level = int(level)-1 | |
choosing = False | |
else: | |
input("> That level does not exist. Press Enter to try again...\n") | |
else: | |
level = 0 | |
choosing = False | |
input("> That was not a valid level, so we'll start from the beginning...\n") | |
elif mode=="3": | |
state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelSandbox() | |
level = 0 | |
elif mode=="4": | |
allowed_filenames = ["0000","0001","0010","0011", "0100","0101","0110","0111", "1000","1001","1010","1011", "1100","1101","1110","1111"] | |
input("\n> This mode relates to a Jupyter notebook, which you'll find at\n https://github.com/decodoku/Quantum_Programming_Tutorial/tree/master/image-superposer...\n") | |
input("> There you'll find 16 images, all with a bit string as their filename...\n") | |
choosing = True | |
while choosing : | |
string1 = input("> Choose one of these images by typing the filename below...\n") | |
if string1 in allowed_filenames: | |
choosing = False | |
else: | |
input("> That was not a valid filename. Press Enter to try again...\n") | |
choosing = True | |
while choosing : | |
string2 = input("\n> Choose another image typing the filename below...\n") | |
if string2 in allowed_filenames and string2!=string1: | |
choosing = False | |
else: | |
input("> That was not a valid filename. Press Enter to try again...\n") | |
input("\n> You'll now write a QISKit program to superpose these two images...\n") | |
input("\n> This can then be run on a real machine using the Jupyter notebook...\n") | |
state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelSuperposer(string1,string2) | |
level = 0 | |
elif mode=="5": | |
state_list, success_condition_list, qubits_used_list, allowed_gates_list, level_num, intro, outro = GetLevelBell() | |
level = 0 | |
else: | |
print("> Oops! You shouldn't have been allowed to pick this mode. Restart the program and try again...") | |
while (level<level_num) : | |
# specifications for this level | |
state = copy.deepcopy(state_list[level]) | |
allowed_gates = copy.deepcopy(allowed_gates_list[level]) | |
required_gates = copy.deepcopy(allowed_gates) | |
qubits_used = copy.deepcopy(qubits_used_list[level]) | |
success_condition = copy.deepcopy(success_condition_list[level]) | |
bloch = False # always start a level with Bloch off | |
active_qubit = -1 # and no active qubit | |
program = [] # and an empty program | |
# every puzzle is thought of as one involving two qubits, even if only one of those qubits is involved | |
# qubits_used should therefore always be a list of two qubits, the first is the one displayed on the top, and the second is the one on the bottom | |
if allowed_gates[qubits_used[0]]=={} : # if no gates are allowed for the qubit on top, we know to only show the qubit on the side | |
shown_qubit = 1 | |
elif allowed_gates[qubits_used[1]]=={} : # and vice versa | |
shown_qubit = 0 | |
else : | |
shown_qubit = 2 | |
success = False | |
restart = False | |
ClearScreen () | |
print("\nLevel "+str(level+1)+"\n") | |
for line in intro[level] : | |
input("> " + line + "...") | |
while success==False and restart==False : | |
# ask player to choose an operation | |
combined_gates = [] | |
for qubit in [qubits_used[0],qubits_used[1],"both"]: | |
for gate in allowed_gates[qubit].keys() : | |
if allowed_gates[qubit][gate]==0 or required_gates[qubit][gate]>0: | |
if gate not in combined_gates: | |
combined_gates.append(gate) | |
gate = "" | |
while gate=="": | |
message = "> Choose one of the allowed operations from the list above by typing its name below\n> Or type restart to start this puzzle over..." | |
given_input = PrintScreen ( message, level, intro, program, state, shown_qubit, active_qubit, bloch, allowed_gates, required_gates ) | |
if given_input in combined_gates or given_input=='restart' : | |
gate = given_input | |
# ask player for a qubit to act on (if there is a choice)... | |
qubit = "" | |
if gate in ["cz","unbloch","restart"]: # for gates that act symmetrically the choice is irrelevant, and so set by default to both | |
qubit = "both" | |
elif shown_qubit==0 : # if only the top qubit is shown, that's what the gate acts on | |
qubit = qubits_used[0] | |
elif shown_qubit==1 : # if only the side qubit is shown, that's what the gate acts on | |
qubit = qubits_used[1] | |
elif gate not in allowed_gates[qubits_used[0]].keys(): # if the gate isn't an allowed one for the top qubit, it acts on the side | |
qubit = qubits_used[1] | |
elif gate not in allowed_gates[qubits_used[1]].keys(): # and vice-versa | |
qubit = qubits_used[0] | |
else : | |
while qubit not in [qubits_used[0],qubits_used[1]]: | |
message = "> Choose a qubit to act on:\n> Type in "+qubits_used[0]+" or "+qubits_used[1]+"..." | |
qubit = PrintScreen ( message, level, intro, program, state, shown_qubit, active_qubit, bloch, allowed_gates, required_gates ) | |
# if it is a gate, apply it | |
if gate in ["x","z","h","q","qdg","cz","cx"] : | |
# the apply gate function adresses qubits as 0 and 1, so we convert back to this before applying | |
if qubit==qubits_used[0] : | |
qubit_pos = "0" | |
elif qubit==qubits_used[1] : | |
qubit_pos = "1" | |
else : | |
qubit_pos = "both" | |
# now apply | |
state = ApplyGate( state, gate, qubit_pos ) | |
# then we write the qiskit commands | |
WriteQISKit( gate, qubit, qubits_used, program, mode ) | |
# if it is a visualization command, apply it | |
elif gate=="bloch" : | |
bloch = True | |
if qubit==qubits_used[0] : | |
active_qubit = 0 | |
elif qubit==qubits_used[1] : | |
active_qubit = 1 | |
elif gate=="unbloch" : | |
bloch = False | |
active_qubit = -1 | |
elif gate=="restart" : | |
restart = True | |
else : | |
print("Error: Something's not quite right") | |
# log the number of these gates if it is important | |
if gate!="restart" : | |
if allowed_gates[qubit][gate] > 0 : | |
required_gates[qubit][gate] -= 1 | |
if required_gates[qubit][gate] < 0 : | |
input("> You have used this gate too many times, so the level will restart...\n") | |
restart = True | |
# see if success conditions are met | |
success = True | |
# the final state has to be right | |
for box, expect in success_condition.items() : | |
success = success and state[box]==expect | |
# and the number of ops has to be right | |
for qubit in required_gates.keys() : | |
for gate in required_gates[qubit].keys() : | |
if (required_gates[qubit][gate] > 0) : | |
success = False | |
if restart==False : | |
message = "\n> Target achieved.\n\n\n> Press Enter to continue..." | |
given_input = PrintScreen ( message, level, intro, program, state, shown_qubit, active_qubit, bloch, {}, required_gates ) | |
# print the outro | |
for line in outro[level] : | |
input("> " + line + "...") | |
# interate the level | |
level += 1 | |
if mode in ["1","2"] : | |
input("> That's all the levels we have for now\nRestart the program to explore the other modes, or continue your quantum journey at ibm.biz/helloquantum\n") | |
elif mode=="3" : | |
input("> How are you seeing this?!?!?!?!?!?!?!\n") | |
elif mode=="4" : | |
input("> Now you have your QISKit program. You just need to run the notebook for your image.\nhttps://github.com/decodoku/Quantum_Programming_Tutorial\n") | |
elif mode=="4" : | |
input("> Now you have your QISKit program. You just need to run the notebook see what it d.\nhttps://github.com/decodoku/Quantum_Programming_Tutorial/tree/master/bell-test\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Perhaps there should be a comma at the end of line 257 in Levels.py?