## Enter Team ID 
import os 
os.environ["TEAMID"] = "Excalibur"

from qiskit import QuantumCircuit
from numpy import *

def qram_4q(m, array):
    ### your code here
    size=int(floor(log2(m))+3)
    n=size-2
    qc=QuantumCircuit(size)
    binary=[]
    k=str(n)
    for i in array:
        binary.append(format(i, f'0{k}b'))
    i=0
    qc.h(0)
    qc.h(1)
    qc.x(0)
    qc.x(1)
    for j in range(1,n+1):
        if(binary[i][j-1]=='1'):
            qc.ccx(0,1,size-j)
    i=i+1
    qc.x(0)
    qc.x(1)
    qc.x(1)
    for j in range(1,n+1):
        if(binary[i][j-1]=='1'):
            qc.ccx(0,1,size-j)
    i=i+1
    qc.x(1)
    qc.x(0)
    for j in range(1,n+1):
        if(binary[i][j-1]=='1'):
            qc.ccx(0,1,size-j)
    i=i+1
    qc.x(0)
    for j in range(1,n+1):
        if(binary[i][j-1]=='1'):
            qc.ccx(0,1,size-j)
    return qc
    ### your code here 
    

def test_function_1():
    m = 6
    array = [3, 4, 5, 6]
    qram = qram_4q(m, array)
    return qram 

test_function_1().draw('mpl')

from grader.graders.problem_5.grader import grader1 
grader1.evaluate(qram_4q)

def qram_general(n, m, array):
    
    ### your code here 
    k=int(floor(log2(m))+1)
    l=int(log2(n))
    size=k+l
    qc=QuantumCircuit(size)
    index=list(range(l))
    binary=[]
    for i in array:
        binary.append(format(i, f'0{k}b'))
    qc.h(index)
    for i in range(n):
        b=format(i,f'0{l}b')
        inverted=[]
        for p in range(0,l):
            if(b[p]=='0'):
                qc.x(l-p-1)
                inverted.append(l-p-1)
        for j in range(1,k+1):
            if(binary[i][j-1]=='1'):
                qc.mct(index,size-j)
        for q in inverted:
            qc.x(q)
    return qc
    ### your code here 
    

def test_function_2():
    n = 4
    m = 4
    array = [3,4,5,6]
    qram = qram_general(n, m, array)
    return qram 


test_function_2().draw('mpl')

from grader.graders.problem_5.grader import grader2 
grader2.evaluate(qram_general)

from qiskit.circuit.library import RYGate,RXGate,RZGate
def qram_rotations(n, rotations):
    
    ### your code here 
    l=int(log2(n))
    size=l+1
    qc=QuantumCircuit(size)
    index=list(range(l))
    full=list(range(size))
    qc.h(index)
    for i in range(n):
        b=format(i,f'0{l}b')
        inverted=[]
        for p in range(0,l):
            if(b[p]=='0'):
                qc.x(l-p-1)
                inverted.append(l-p-1)
        qc.barrier()
        if(rotations[i][0]=='x'):
            multirx = RXGate(rotations[i][1]*2*pi).control(l,label=None)
            qc.append(multirx,full)
        elif(rotations[i][0]=='y'):
            multiry = RYGate(rotations[i][1]*2*pi).control(l,label=None)
            qc.append(multiry,full)
        elif(rotations[i][0]=='z'):
            multirz = RZGate(rotations[i][1]*2*pi).control(l,label=None)
            qc.append(multirz,full)
        qc.barrier()
        for q in inverted:
            qc.x(q)
        qc.barrier()
    return qc
    ### your code here 

def test_function_3():
    n = 8
    rotations = [('x', 0.123), ('y', -0.912),('z',-0.12),('x', 0.5),('z',0.5),('y', -0.5),('z',0.5),('x', 0.5)]
    
    qram = qram_rotations(n, rotations)
    return qram 


test_function_3().draw('mpl')

from grader.graders.problem_5.grader import grader3 
grader3.evaluate(qram_rotations)

