import argparse
import re
def process_qasm(fname):
qgates = ['H','X','CNOT','Y','Z','S','T','Tdag','Sdag','Rx','Ry','Rz','PrepX','PrepZ','MeasX','MeasZ','Toffoli','Fredkin']
qgates_1 = ['H','X','Y','Z','S','T','Tdag']
qgates_1a = ['Sdag']
qgates_2 = ['CNOT']
qgates_3 = ['Toffoli','Fredkin']
qgates_4 = ['PrepX','PrepZ']
qgates_5 = ['MeasX','MeasZ']
qgates_6 = ['Rx','Ry','Rz']
qgates_7 = ['afree']
gateNames = {
'H':'H',
'X':'X',
'Y':'Y',
'Z':'Z',
'S':'S',
'T':'T',
'Sdag':'Sdag',
'Tdag':'Tdag',
'PrepX':'PrepX', #'Px',
'PrepZ':'PrepZ', #'Pz',
'MeasZ':'MeasZ', #'Mz',
'MeasX':'MeasX', #'Mx',
'Rx':'Rx',
'Ry':'Ry',
'Rz':'Rz',
'CNOT':'CNOT', #'CX',
'Toffoli':'Tof',
'Fredkin':'Fredkin',
'afree':'afree'
}
pattern_qbit_decl = re.compile(r"\s*\bqbit\b\s+(?P<qbit_var>\w+)\s*\[\s*(?P<array_size>\d+)\s*\]\s*;")
pattern_cbit_decl = re.compile(r"\s*\bcbit\b\s+(?P<qbit_var>\w+)\s*\[\s*(?P<array_size>\d+)\s*\]\s*;")
pattern_qg = re.compile(r"\s*((\w+|\w+\[(.*?)\])\s*\=)*\s*(?P<func_name>\w+)\s*\(\s*(?P<array_size>(.*?))\s*\)\s*;")
pattern_qbit_arg = re.compile(r"(.*?)\((.*?)\bqbit\b\s*(.*?)\)(.*?)")
pattern_meas = re.compile(r"\s*(?P<func_ret>(\w+|\w+\[(.*?)\])\s*\=)*\s*(\bqg_MeasX|qg_MeasZ\b)\s*\(\s*(?P<array_size>(.*?))\s*\)\s*;")
pattern_main = re.compile(r"\s*(\bvoid|module\b)\s+(\bmain|main1\b)\s*\((.*?)\)\s*(\{)*\s*")
pattern_comment = re.compile(r"\s*//--//--(.*?)--//--//\s*")
fout_name = re.sub('\.qasmh$','_qasm.scaffold',fname)
fout = open(fout_name,'w')
fout.write('#include<stdio.h>\n')
#add instrumentation functions
for q in qgates_1:
instFnName = 'qg_'+q
fstr = 'void '+instFnName+'(char* a){ printf("' +gateNames[q] +' %s\\n",a); }\n'
fout.write(fstr)
fout.write('\n')
for q in qgates_1a: #Sdag = S^3
instFnName = 'qg_'+q
fstr = 'void '+instFnName+'(char* a){ printf("S %s\\n",a); printf("S %s\\n",a); printf("S %s\\n",a); }\n'
fout.write(fstr)
fout.write('\n')
for q in qgates_2: #CNOT => CX (target,control)
instFnName = 'qg_'+q
fstr = 'void '+instFnName+'(char* a, char* b){ printf("'+gateNames[q]+' %s,%s\\n",a,b); }\n'
fout.write(fstr)
fout.write('\n')
for q in qgates_3:
instFnName = 'qg_'+q
fstr = 'void '+instFnName+'(char* a, char* b, char* c){ printf("' +gateNames[q] +' %s,%s,%s\\n",a,b,c); }\n'
fout.write(fstr)
fout.write('\n')
for q in qgates_4: #PrepZ, PrepX
instFnName = 'qg_'+q
fstr = 'void '+instFnName+'(char* a, int i){ printf("' +gateNames[q] +' %s\\n",a); '
fout.write(fstr)
fstr = 'if(i==1){ printf("X %s\\n",a); } }\n'
fout.write(fstr)
fout.write('\n')
for q in qgates_5: #MeasX, MeasZ
instFnName = 'qg_'+q
fstr = 'void '+instFnName+'(char* a){ printf("' +gateNames[q] +' %s\\n",a); }\n'
fout.write(fstr)
fout.write('\n')
for q in qgates_6:
instFnName = 'qg_'+q
fstr = 'void '+instFnName+'(char* a, double b){ printf("' +gateNames[q] +' %s,%f\\n",a,b); }\n'
fout.write(fstr)
for q in qgates_7:
instFnName = q
fstr = 'void '+instFnName+'(char** a, int b ){ for(int i = 0; i < b; i++){ printf("' +gateNames[q] +' %s\\n",(*a)); a++; }}\n'
fout.write(fstr)
fout.write('\n')
#ignore contents until QASM Generation Pass
f = open(fname,'r')
b = 'Dummy Line'
while(b!=''):
if(b.find('QASM Generation Pass:')!=-1):
break
b = f.readline()
b = f.readline()
inMainFunc = False
setQbitDecl = []
setCbitDecl = []
while(b!=''):
if(b.find('End of QASM generation')!=-1):
break
#check for qbit declarations
m = re.match(pattern_main,b)
if(m):
inMainFunc = True
b = re.sub(r"\bvoid|module\b","int ",b)
m = re.match(pattern_qbit_decl,b)
if(m): #Matched qbit declaration
numElem = int(m.group('array_size'))
var = m.group('qbit_var')
addAlphabet=''
if(not inMainFunc):
addAlphabet='a' #add 'a' at end of ancilla declaration
subStr = "char* "+m.group('qbit_var')+'['+m.group('array_size')+'] = {'
fout.write(subStr)
for i in range(numElem-1):
varName = var+str(i)+addAlphabet
tmp = '"'+varName+'",'
if varName not in setQbitDecl:
setQbitDecl.append(varName)
fout.write(tmp)
varName = var+str(numElem-1)+addAlphabet
tmp = '"'+varName+'"'
if varName not in setQbitDecl:
setQbitDecl.append(varName)
fout.write(tmp)
fout.write('};\n')
else:
m = re.match(pattern_qg,b)
if(m): #Matched qauntum gate call
qstr = m.group('func_name')
if qstr in qgates:
rstr = 'qg_'+qstr
mystr = b.replace(qstr,rstr)
#check for Meas gates
m1 = re.match(pattern_meas,mystr)
if(m1):
retStr = m1.group('func_ret')
if(retStr):
mystr = mystr.replace(retStr,'')
fout.write(mystr)
else:
fout.write(b)
else:
#substitute qbit as char* in module definitions
m = re.match(pattern_qbit_arg,b)
if(m):
mystr = b
mystr = re.sub(r"\bqbit\b","char* ",mystr)
fout.write(mystr)
else:
m = re.match(pattern_cbit_decl,b)
if(m):
numElem = int(m.group('array_size'))
var = m.group('qbit_var')
subStr = "char* "+m.group('qbit_var')+'['+m.group('array_size')+'] = {'
fout.write(subStr)
for i in range(numElem-1):
tmp = '"'+var+str(i)+'",'
setCbitDecl.append(var+str(i))
fout.write(tmp)
tmp = '"'+var+str(numElem-1)+'"'
setCbitDecl.append(var+str(numElem-1))
fout.write(tmp)
fout.write('};\n')
else:
m = re.match(pattern_comment,b)
if(m):
subStr = 'printf("'+b.rstrip('\n')+'\\n");'
fout.write(subStr)
else:
#print 'Did not match any pattern:',b
fout.write(b)
b = f.readline()
f.close()
fout.close()
#write qbit and cbit declarations to file
fdecl = open("fdecl.out",'w')
for q in setQbitDecl:
myStr = 'qubit '+q+'\n'
fdecl.write(myStr)
for q in setCbitDecl:
myStr = 'cbit '+q+'\n'
fdecl.write(myStr)
fdecl.close()
parser = argparse.ArgumentParser(description='Convert QASM code into flattened QASM code')
parser.add_argument("input")
args = parser.parse_args()
process_qasm(args.input)