# Writing a Phase Estimation function in Cirq

I am trying to write a phase estimation algorithm using Cirq. The algorithm works for different inputs but I receive a few errors in the estimate_phi(mystery) function.

from cirq import CZPowGate

def create_operator(phi):
CU = CZPowGate(exponent = phi*2)
return CU

def iqft(n,qubits,circuit):

#Swap the qubits
for i in range(n//2):
circuit.append(SWAP(qubits[i],qubits[n-i-1]), strategy = InsertStrategy.NEW)

#For each qubit
for i in range(n-1,-1,-1):
#Apply CR_k gates where j is the control and i is the target
for j in range(n-1,i,-1):
#Define and apply CR_k gate
crk = CZPowGate(exponent = -2/2**(k))
circuit.append(crk(qubits[j],qubits[i]),strategy = InsertStrategy.NEW)
k=k-1 #Decrement at each step

circuit.append(H(qubits[i]),strategy = InsertStrategy.NEW)

def qpe(t,control, target, circuit, CU):

circuit.append(cirq.H.on_each(control))

#Apply CU gates
for i in range(t):
#Obtain the power of CU gate
CUi = CU**(2**i)
#Apply CUi gate where t-i-1 is the control
circuit.append(CUi(control[t-i-1],*target))

#Apply inverse QFT
iqft(t,control,circuit)


This script works for different inputs:

import cirq
from cirq.circuits import InsertStrategy
from cirq          import H, X, SWAP, CZPowGate
# def estimate_phi(mystery):
mystery = 0.30
#     Let the size of the first register equal 10.
n = 1

for t in range (1,10):
#Create cirucit
circuit = cirq.Circuit()

#Create t control qubits
control = [cirq.LineQubit(i) for i in range(t) ]

#Create n target qubits
target = [cirq.LineQubit(i) for i in range(t, t + n) ]

#Set target qubit to state |1>
circuit.append(X.on_each(target))

#Apply QPE
CU = create_operator(mystery)
qpe(t,control, target, circuit, CU)

circuit.append(cirq.measure(*control, key = 'result'))

s       = cirq.Simulator()
samples = s.run(circuit, repetitions = 1000)

#Most frequent observation
freq = list(samples.histogram(key = 'result').keys())
print("t:", t,"estimation:", freq/2**t)


but when I put it in a function, I receive two errors for the print(test_qpe(0.23)) command

unsupported operand type(s) for ** or pow(): 'complex' and 'LinearCombinationOfGates'

During handling of the above exception, another exception occurred: Simulator doesn't support (cirq.CZcirq.LinearCombinationOfGates({(cirq.CZ0.46): 2})).on(cirq.LineQubit(0), cirq.LineQubit(1))

import cirq
from cirq.circuits import InsertStrategy
from cirq          import H, X, SWAP, CZPowGate

def estimate_phi(mystery):

for t in range (1,10):
#Create cirucit
circuit = cirq.Circuit()
#Number of qubits in the register storing eigenvector
n = 1

#Create t control qubits
control = [cirq.LineQubit(i) for i in range(t) ]

#Create n target qubits
target = [cirq.LineQubit(i) for i in range(t, t + n) ]

#Set target qubit to state |1>
circuit.append(X.on_each(target))

#Apply QPE
CU = create_operator(mystery)
qpe(t,control, target, circuit, CU)

circuit.append(cirq.measure(*control, key = 'result'))

s       = cirq.Simulator()
samples = s.run(circuit, repetitions = 1000)

#Most frequent observation
freq = list(samples.histogram(key = 'result').keys())

return freq/2**t

import math
def test_qpe(phi):
operator = CZPowGate(exponent=2*phi)
return estimate_phi(operator)


You are passing estimate_phi the an operator: CZPowGate(exponent=2*phi). Then in estimate_phi this operator becomes the mystery parameter. You then take this mystery variable and call create_operator on it. In create_operator this means that CU = CZPowGate(exponent = phi*2) is really CU = CZPowGate(CZPowGate(exponent=2*phi)). So you are creating a CZ raised to a CZ!
I think what you want to do is to pass in 2*phi in the test_qpe function.
Also, for creating the line qubits, you might be interested in the class function LineQubit.range which is just like python's range but returns LineQubits instead.