# A Quantum Circuit to Construct All Maximal Cliques Using Grover’s Search Algorithm

## Chu Ryang Wie

### DOI: https://arxiv.org/abs/1711.06146v2

from sympy import *
#import sympy.physics.quantum as qp # quantum physics
from sympy.physics.quantum.qubit import *
from sympy.physics.quantum import Dagger, TensorProduct
from sympy.physics.quantum.gate import *
from sympy.physics.quantum.qapply import *

N = Symbol('N', integer=True)
#N = 8

# base network G:
# 1 <-> 2 <-> 3
# Nodes: 1, 2, 3
# Edges: (1,2), (2,3)

# Adjacency matrix for network G
A = Matrix([
	[0, 1, 0],
	[1, 0, 1],
	[0, 1, 0]
])

# creating qubits for n=3 basis
q = [Qubit(f'{dummy:03b}') for dummy in range(2**3)]
q

# creating psi state vector
kpsi = 1/sqrt(N)*sum(q)
bpsi = 1/sqrt(N)*Dagger(sum(q))

# TODO: create in terms of matrices the O operator perfectly as the circuit described in the paper
O = Matrix([
    [1, 0, 0, 0, 0, 0, 0, 0],
    [0, 1, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 0,-1, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 0, 0],
    [0, 0, 0, 0, 0, 1, 0, 0],
    [0, 0, 0, 0, 0, 0,-1, 0],
    [0, 0, 0, 0, 0, 0, 0, 1],
])

# step: constructing the U operator basics using a network with n=3
# function to represent qubit as matrix: qubit_to_matrix()

U = 2*kpsi*bpsi
U = qubit_to_matrix(U)-Matrix.eye(2**3)

Hm = Matrix([[1,1],[1,-1]])
Hc = 1/sqrt(2)

H3 = Hc**3*kronecker_product(Hm,Hm,Hm)

q000 = qubit_to_matrix(q[0])
Ualt = H3*(2*q000*Dagger(q000)-Matrix.eye(8))*H3

def G(kpsi):
    return matrix_to_qubit(U*O*qubit_to_matrix(kpsi))

# working with a network made by two nodes
# n = 2
# Nodes: 0, 1
# Edges: (0,1)
A = Matrix([
    [0,1],
    [1,0]
])

# tentando reescrever as contas utilizando seno e cosseno
theta = Symbol('theta')
# creating psi state vector
kpsi = sin(theta/2)*1/sqrt(1)*(Qubit(1,1)) + cos(theta/2)*1/sqrt(3)*(Qubit(0,0)+Qubit(0,1)+Qubit(1,0))
bpsi = sin(theta/2)*1/sqrt(1)*Dagger(Qubit(1,1)) + cos(theta/2)*1/sqrt(3)*Dagger(Qubit(0,0)+Qubit(0,1)+Qubit(1,0))

U = 2*kpsi*bpsi
U = qubit_to_matrix(U)-Matrix.eye(2**2)

O = Matrix([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [0, 0, 0,-1]
])

# Creating Oracle based on paper algorithm
def O_operator(ket):
    
    pass





# teste
Matrix.eye(8) - 2 * qubit_to_matrix(Qubit(0,0,0)*Dagger(Qubit(0,0,0)))

X = Matrix([
    [0,1],
    [1,0]
])

X

Z = Matrix([
    [1,0],
    [0,-1]
])

Tp = TensorProduct
X3 = Tp(Tp(Matrix.eye(2),Matrix.eye(2)),X)

Z3 = Matrix([
    [1,0,0,0,0,0,0,0],
    [0,-1,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0],
    [0,0,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0],
    [0,0,0,0,0,1,0,0],
    [0,0,0,0,0,0,1,0],
    [0,0,0,0,0,0,0,1],
])

X3*Z3*X3

a= H3*4/sqrt(2)

p=sqrt(2)/4*a*Matrix([1,1,1,-1,1,1,-1,1])

sqrt(2)/4*a*Matrix([1,0,-1,0,0,-1,0,1])

X.as_matrix()

Tp = TensorProduct
XX = Tp(Tp(Matrix([[0,1],[1,0]]),Matrix([[0,1],[1,0]])),Matrix([[0,1],[1,0]]))

Z3 = Matrix([
    [1,0,0,0,0,0,0,0],
    [0,1,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0],
    [0,0,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0],
    [0,0,0,0,0,1,0,0],
    [0,0,0,0,0,0,1,0],
    [0,0,0,0,0,0,0,-1],
])

XX*Z3*XX

XX*Z3


Z3*XX


HH = Tp(Tp(Matrix([[1,1],[1,-1]]),Matrix([[1,1],[1,-1]])),Matrix([[1,1],[1,-1]]))

HH

HH*XX*HH

CX = Matrix([
    [1,0,0,0,0,0,0,0],
    [0,1,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0],
    [0,0,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0],
    [0,0,0,0,0,1,0,0],
    [0,0,0,0,0,0,0,1],
    [0,0,0,0,0,0,1,0],
])

XX*HH*CX*HH*XX

HH*(2*Matrix([1,0,0,0,0,0,0,0])*Dagger(Matrix([1,0,0,0,0,0,0,0]))-Matrix.eye(8))*HH

CZ = Matrix([
    [1,0,0,0,0,0,0,0],
    [0,1,0,0,0,0,0,0],
    [0,0,1,0,0,0,0,0],
    [0,0,0,1,0,0,0,0],
    [0,0,0,0,1,0,0,0],
    [0,0,0,0,0,1,0,0],
    [0,0,0,0,0,0,1,0],
    [0,0,0,0,0,0,0,-1]
])

XX*CZ*XX

HH*CX*HH

HH*XX*CZ*XX*HH

CZ

CX

H3 = kronecker_product(Matrix.eye(2),Matrix.eye(2),Matrix([[1,1],[1,-1]]))
H3

HH*XX*H3*CX*H3*XX*HH

