#!/usr/bin/env python # coding: utf-8 # # Loops at English File level using Loop Files # # Before reading this notebook, we recommend that you first learn how to use placeholders in Qubiter, # because placeholders and loops at the English file level are both used heavily in this notebook. They both go naturally together. Placeholder usage is illustrated in the notebook called `examples_of_placeholder_usage.ipynb` located in the same folder as this one. # # You can have loops at either the Python library level or the machine language level (i.e., English file). Both accomplish the same purpose. This notebook is only important to you if you want to use loops in an English file. The following talk explains some of the motivation and pros and cons of doing this. # # http://www.ar-tiste.com/jan2019QubiterPlaceholderAndLoops.pdf # # First, change your working directory to the Qubiter directory in your computer and add its path to the path environment variable. # In[1]: import os import sys print(os.getcwd()) os.chdir('../../') print(os.getcwd()) sys.path.insert(0,os.getcwd()) # The next code writes English and Picture files for a circuit which contains # 2 nested loops and many placholder variables of # either the hash followed by variable number type (e.g., `#9`) # or the functional type (e.g., `-my_fun#1#2`) # In[2]: # some neccessary imports from qubiter.SEO_writer import * from qubiter.SEO_simulator import * from qubiter.StateVec import * from qubiter.LoopFileGenerator import * # In[3]: file_prefix = 'loop_gen_test' num_qbits = 4 # write the English and Picture files emb = CktEmbedder(num_qbits, num_qbits) wr = SEO_writer(file_prefix, emb) wr.write_controlled_one_qbit_gate(0, Controls.new_single_trol(num_qbits, 2, False), OneQubitGate.rot_ax, ['#1', 1]) wr.write_LOOP(20, nreps=2) wr.write_controlled_one_qbit_gate(1, Controls.new_single_trol(num_qbits, 2, False), OneQubitGate.rot_ax, ['-my_fun1#1#2', 2]) wr.write_LOOP(10, nreps=4) wr.write_controlled_one_qbit_gate(2, Controls.new_single_trol(num_qbits, 3, True), OneQubitGate.rot, ['-#1*.5', '#2', '-my_fun3#3']) wr.write_NEXT(10) wr.write_controlled_one_qbit_gate(1, Controls.new_single_trol(num_qbits, 2, False), OneQubitGate.rot_ax, ['my_fun1#1#2', 2]) wr.write_NEXT(20) wr.write_controlled_one_qbit_gate(0, Controls.new_single_trol(num_qbits, 2, False), OneQubitGate.rot_ax, ['#1*.3', 1]) wr.write_one_qbit_gate(1, OneQubitGate.rot_ax, ['my_fun#1', 1]) wr.close_files() # The effect of the preceding code was to write the following English and Picture files # # * ../io_folder/loop_gen_test_4_eng.txt # * ../io_folder/loop_gen_test_4_ZLpic.txt # One can write a log file with info about the circuit just created simply by # creating an object of the class SEO_reader with the flag `write_log` set to True. # In[4]: # write a log SEO_reader(file_prefix, num_qbits, write_log=True) # The preceding line of code created the following log file # * ../io_folder/loop_gen_test_4_log.txt # The next code reads the English file just created and writes what we call a "Loop File". # In[5]: # write a Loop File LoopFileGenerator(file_prefix, num_qbits) # The preceding code created the following Loop File. # # * ../io_folder/loop_gen_test_4_loop.py # # Note that the line numbers given in the Loop file comments refer to lines in the English file. As you can see, a Loop file is a Python script # with the same loop structure as the English file. You are supposed to # copy the Loop file, give it a slightly different name, and modify it. We call the copy of the Loop file a "Loop xfile" (x for executable, because we intend to run it with exec()) The Loop xfile should have the same name as the Loop file # except for a non-negative number that you insert between the word "loop" and the ending ".py". # # Next is a Loop xfile that we created from the above Loop file # # * ../io_folder/loop_gen_test_4_loop1.py # # Note that the original Loop file has a line for each time a hash variable makes an appearance # and for each time a function variable makes an appearance. The original Loop file # gives a value of `None` to all appearances (uses) of each variable. You have # a choice of replacing each None by a suitable value (in which case you are assigning it a new value) or leaving it as None. If you # leave a variable as None, Qubiter will assume that you want it to take the value that was assigned to it the most recent time in its past that it was assigned a value different from None. This assumes that at the very least, the first time that the variable makes an appearance, its value is replaced from None to something else and suitable. # Next, we create an object of the class SEO_simulator # with the flag `xfile_number` equal to a non-negative number. The default value of that flag is -1, so any non-negative number tells the simulator object to execute a Loop xfile which ends with that xfile_num followed by ".py". In our example, xfile_num=1 # # Creating an object of SEO_simulator first executes the xfile and then # runs through the circuit in the English file, duly jumping back to the matching LOOP line every time # a NEXT is encountered, until the full number of repetitions (reps) has been performed. # The report at the end of this notebook means that Qubiter succeeded in traversing through the circuit, using the info that it got from executing the xfile to correctly resolve the angle value of each gate. # # In[6]: # read a Loop xfile and do simulation sim = SEO_simulator(file_prefix, num_qbits, verbose=False, xfile_num=1) print("\n----------------------------------------") StateVec.describe_st_vec_dict(sim.cur_st_vec_dict)