├── README.md └── main.py /README.md: -------------------------------------------------------------------------------- 1 | # Quantum-Viewer 2 | 3 | ### Note: 4 | No Conda virtual environment or Jupyter was used for this project. 5 | 6 | ### About: 7 | 8 | ![image](https://user-images.githubusercontent.com/64016811/234301933-90c9c2b9-3238-4d12-bb05-fe61ce9d48ee.png) 9 | 10 | 11 | ### Techs used: 12 | 13 | - Python 14 | - Tkinter 15 | - Qiskit 16 | 17 | ### Installables: 18 | 19 | ```pip install numpy``` 20 | ```pip install qiskit``` 21 | ```pip install matlplotlib``` 22 | 23 | ### Screenshots: 24 | 25 | ![image](https://user-images.githubusercontent.com/64016811/234300522-da054835-e2ec-46ba-9dc7-b7c565d34902.png) 26 | ![image](https://user-images.githubusercontent.com/64016811/234301542-f3a19895-9bdd-44bd-8a23-3bbb46cf8f20.png) 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import tkinter 2 | from tkinter import LEFT, END, DISABLED, NORMAL 3 | import warnings 4 | import numpy as np 5 | import qiskit 6 | from qiskit import QuantumCircuit 7 | from qiskit.visualization import visualize_transition 8 | 9 | # Ignore unnecessary warnings 10 | warnings.simplefilter("ignore") 11 | 12 | # Define Window 13 | root = tkinter.Tk() 14 | root.title('Quantum Viewer') 15 | 16 | # set the icon 17 | 18 | root.geometry('400x360') 19 | root.resizable(0,0) # Blocking the resizing feature 20 | 21 | # Define the colors and fonts 22 | background = 'lightgreen' 23 | buttons = 'lightblue' 24 | special_buttons = 'orange' 25 | button_font = ('Arial', 18) 26 | display_font = ('Arial', 32) 27 | 28 | # Initialize the Quantum Circuit 29 | def initialize_circuit(): 30 | global circuit 31 | circuit = QuantumCircuit(1) 32 | 33 | initialize_circuit() 34 | 35 | 36 | theta = 0 37 | 38 | # Define Functions 39 | # Define functions for non-qiskit buttons 40 | def display_gate(gate_input): 41 | """ 42 | Adds a corresponding gate notation in the display to track the operations. 43 | If the number of operation reach ten, all gate buttons are disabled. 44 | """ 45 | # Insert the defined gate 46 | display.insert(END,gate_input) 47 | 48 | # Check if the number of operations has reached ten, if yes, 49 | # disable all the gate buttons 50 | input_gates = display.get() 51 | num_gates_pressed = len(input_gates) 52 | list_input_gates = list(input_gates) 53 | search_word = ["R","D"] 54 | count_double_valued_gates = [list_input_gates.count(i) for i in search_word] 55 | num_gates_pressed-=sum(count_double_valued_gates) 56 | if num_gates_pressed==10: 57 | gates = [x_gate, y_gate, z_gate, Rx_gate, Ry_gate, Rz_gate, s_gate, sd_gate, t_gate, td_gate, hadamard] 58 | for gate in gates: 59 | gate.config(state=DISABLED) 60 | 61 | def clear(circuit): 62 | """ 63 | Clears the display! 64 | Reintializes the Quantum Circuit for fresh calculation! 65 | Checks if the gate buttons are disabled, if so, enables the buttons 66 | """ 67 | # clear the display 68 | display.delete(0, END) 69 | 70 | # reset the circuit to initial state |0> 71 | initialize_circuit() 72 | 73 | # Checks if the buttons are disabled and if so, enables them 74 | if x_gate['state']==DISABLED: 75 | gates = [x_gate, y_gate, z_gate, Rx_gate, Ry_gate, Rz_gate, s_gate, sd_gate, t_gate, td_gate, hadamard] 76 | for gate in gates: 77 | gate.config(state=NORMAL) 78 | 79 | def about(): 80 | """ 81 | Displays the info about the project! 82 | """ 83 | info = tkinter.Tk() 84 | info.title('About') 85 | info.geometry('650x470') 86 | info.resizable(0,0) 87 | 88 | text = tkinter.Text(info, height = 20, width = 20) 89 | 90 | # Create label 91 | label = tkinter.Label(info, text = "About Quantum Viewer:") 92 | label.config(font =("Times New Roman", 16)) 93 | 94 | 95 | text_to_display = """ 96 | About: Visualization tool for Single Qubit Rotation on Bloch Sphere 97 | 98 | Created by : Mainak Chaudhuri 99 | Created using: Python, Tkinter, Qiskit 100 | 101 | Info about the gate buttons and corresponding qiskit commands: 102 | 103 | X = flips the state of qubit - circuit.x() 104 | Y = rotates the state vector about Y-axis - circuit.y() 105 | Z = flips the phase by PI radians - circuit.z() 106 | Rx = parameterized rotation about the X axis - circuit.rx() 107 | Ry = parameterized rotation about the Y axis. circuit.ry() 108 | Rz = parameterized rotation about the Z axis. circuit.rz() 109 | S = rotates the state vector about Z axis by PI/2 radians - circuit.s() 110 | T = rotates the state vector about Z axis by PI/4 radians - circuit.t() 111 | Sd = rotates the state vector about Z axis by -PI/2 radians - circuit.sdg() 112 | Td = rotates the state vector about Z axis by -PI/4 radians - circuit.tdg() 113 | H = creates the state of superposition - circuit.h() 114 | 115 | For Rx, Ry and Rz, 116 | theta(rotation_angle) allowed range in the app is [-2*PI,2*PI] 117 | """ 118 | 119 | label.pack() 120 | 121 | text.pack(fill='both',expand=True) 122 | 123 | # Insert the text 124 | text.insert(END,text_to_display) 125 | 126 | # run 127 | info.mainloop() 128 | 129 | 130 | def change_theta(num,window,circuit,key): 131 | """ 132 | CHanges the global variable theta and destroys the window 133 | """ 134 | global theta 135 | theta = num * np.pi 136 | if key=='x': 137 | circuit.rx(theta,0) 138 | theta = 0 139 | elif key=='y': 140 | circuit.ry(theta,0) 141 | theta = 0 142 | else: 143 | circuit.rz(theta,0) 144 | theta = 0 145 | window.destroy() 146 | 147 | def user_input(circuit,key): 148 | """ 149 | Take the user input for rotation angle for parameterized 150 | Rotation gates Rx, Ry, Rz. 151 | """ 152 | 153 | # Initialize and define the properties of window 154 | get_input = tkinter.Tk() 155 | get_input.title('Get Theta') 156 | get_input.geometry('360x160') 157 | get_input.resizable(0,0) 158 | 159 | val1 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='PI/4',command=lambda:change_theta(0.25,get_input,circuit,key)) 160 | val1.grid(row=0, column=0) 161 | 162 | val2 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='PI/2',command=lambda:change_theta(0.50,get_input,circuit,key)) 163 | val2.grid(row=0, column=1) 164 | 165 | val3 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='PI',command=lambda:change_theta(1.0,get_input,circuit,key)) 166 | val3.grid(row=0, column=2) 167 | 168 | val4 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='2*PI',command=lambda:change_theta(2.0,get_input,circuit,key)) 169 | val4.grid(row=0, column=3,sticky='W') 170 | 171 | nval1 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='-PI/4',command=lambda:change_theta(-0.25,get_input,circuit,key)) 172 | nval1.grid(row=1, column=0) 173 | 174 | nval2 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='-PI/2',command=lambda:change_theta(-0.50,get_input,circuit,key)) 175 | nval2.grid(row=1, column=1) 176 | 177 | nval3 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='-PI',command=lambda:change_theta(-1.0,get_input,circuit,key)) 178 | nval3.grid(row=1, column=2) 179 | 180 | nval4 = tkinter.Button(get_input,height=2,width=10,bg=buttons,font=("Arial",10),text='-2*PI',command=lambda:change_theta(-2.0,get_input,circuit,key)) 181 | nval4.grid(row=1, column=3,sticky='W') 182 | 183 | text_object = tkinter.Text(get_input, height = 20, width = 20,bg="light cyan") 184 | 185 | note = """ 186 | GIVE THE VALUE FOR THETA 187 | The value has the range [-2*PI,2*PI] 188 | """ 189 | 190 | text_object.grid(sticky='WE',columnspan=4) 191 | text_object.insert(END,note) 192 | 193 | 194 | get_input.mainloop() 195 | 196 | # Define functions for qiskit-based buttons 197 | # Define the function for visualize button 198 | def visualize_circuit(circuit,window): 199 | """ 200 | Visualizes the single qubit rotations corresponding to applied gates in a separate tkinter window. 201 | Handles any possible visualization error 202 | """ 203 | try: 204 | visualize_transition(circuit=circuit) 205 | except qiskit.visualization.exceptions.VisualizationError: 206 | window.destroy() 207 | 208 | # Define Layout 209 | # Define the Frames 210 | display_frame = tkinter.LabelFrame(root) 211 | button_frame = tkinter.LabelFrame(root,bg='black') 212 | display_frame.pack() 213 | button_frame.pack(fill='both',expand=True) 214 | 215 | # Define the Display Frame Layout 216 | display = tkinter.Entry(display_frame, width=120, font=display_font, bg=background, borderwidth=2, justify=LEFT) 217 | display.pack(padx=3,pady=4) 218 | 219 | # Define the Button Frame Layout 220 | 221 | # Define the first row of buttons 222 | x_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='X',command=lambda:[display_gate('x'),circuit.x(0)]) 223 | y_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='Y',command=lambda:[display_gate('y'),circuit.y(0)]) 224 | z_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='Z',command=lambda:[display_gate('z'),circuit.z(0)]) 225 | x_gate.grid(row=0,column=0,ipadx=45, pady=1) 226 | y_gate.grid(row=0,column=1,ipadx=45, pady=1) 227 | z_gate.grid(row=0,column=2,ipadx=53, pady=1, sticky='E') 228 | 229 | # Define the second row of buttons 230 | Rx_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='RX',command=lambda:[display_gate('Rx'),user_input(circuit,'x')]) 231 | Ry_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='RY',command=lambda:[display_gate('Ry'),user_input(circuit,'y')]) 232 | Rz_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='RZ',command=lambda:[display_gate('Rz'),user_input(circuit,'z')]) 233 | Rx_gate.grid(row=1,column=0,columnspan=1,sticky='WE', pady=1) 234 | Ry_gate.grid(row=1,column=1,columnspan=1,sticky='WE', pady=1) 235 | Rz_gate.grid(row=1,column=2,columnspan=1,sticky='WE', pady=1) 236 | 237 | # Define the third row of buttons 238 | s_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='S',command=lambda:[display_gate('s'),circuit.s(0)]) 239 | sd_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='SD',command=lambda:[display_gate('SD'),circuit.sdg(0)]) 240 | hadamard = tkinter.Button(button_frame, font=button_font, bg=buttons, text='H',command=lambda:[display_gate('H'),circuit.h(0)]) 241 | s_gate.grid(row=2,column=0,columnspan=1,sticky='WE', pady=1) 242 | sd_gate.grid(row=2,column=1,sticky='WE', pady=1) 243 | hadamard.grid(row=3, column=1, sticky='WENS', pady=1) 244 | 245 | # Define the fifth row of buttons 246 | t_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='T', command=lambda:[display_gate('t'),circuit.t(0)]) 247 | td_gate = tkinter.Button(button_frame, font=button_font, bg=buttons, text='TD',command=lambda:[display_gate('TD'),circuit.tdg(0)]) 248 | t_gate.grid(row=3,column=0,sticky='WE', pady=1) 249 | td_gate.grid(row=2,column=2,sticky='WE', pady=1) 250 | 251 | # Define the Quit and Visualize buttons 252 | quit = tkinter.Button(button_frame, font=button_font, bg=special_buttons, text='Quit',command=root.destroy) 253 | visualize = tkinter.Button(button_frame, font=button_font, bg=special_buttons, text='Visualize',command=lambda:visualize_circuit(circuit,root)) 254 | quit.grid(row=3,column=0,columnspan=1,sticky='WE',ipadx=5, pady=1) 255 | visualize.grid(row=3,column=2,columnspan=1,sticky='WE',ipadx=5, pady=1) 256 | 257 | # Define the clear button 258 | clear_button = tkinter.Button(button_frame, font=button_font, bg=special_buttons, text='Clear',command=lambda:clear(circuit)) 259 | clear_button.grid(row=4,column=0,columnspan=3,sticky='WE') 260 | 261 | # Define the about button 262 | about_button = tkinter.Button(button_frame, font=button_font, bg=special_buttons, text='About',command=about) 263 | about_button.grid(row=5,column=0,columnspan=3,sticky='WE') 264 | 265 | # Run the main loop 266 | root.mainloop() 267 | 268 | --------------------------------------------------------------------------------