# Quantum Phase Estimation¶

The quantum phase estimation (QPE) function estimates the phase of an eigenvector of a unitary function. More precisely, given a unitary function $$F$$ and an input containing a quantum register with a state $$|\psi\rangle$$ such that $$F(|\psi\rangle)=e^{2\pi i\nu}|\psi\rangle$$, the phase estimation function outputs an estimation of $$\nu$$ as a fixed-point binary number.

Phase estimation is frequently used as a subroutine in other quantum algorithms such as Shor's algorithm and quantum algorithms for solving linear systems of equations (HHL algorithm). Theoretical details are in Ref. .

## Syntax¶

Function: PhaseEstimation

Parameters:

• size: int provides the number of digits in the fixed-point representation of the phase.
• unitary: str may be omitted when using the SDK and should otherwise contain the name of the function $$F$$.
• unitary_params: FunctionParams provides the function parameters of the unitary function $$F$$.

## Example¶

This example shows how to perform a simple phase estimation:

1. Initialize the state "10" over two qubits using XGate on the first qubit.
2. Apply a phase estimation on the matrix.
$\begin{pmatrix} 0 & 0 & 0 & 0 \\ 0 & \tfrac{1}{4} & 0 & 0 \\ 0 & 0 & \tfrac{1}{2} & 0 \\ 0 & 0 & 0 & \tfrac{3}{4} \\ \end{pmatrix}$

The output register is in the state "10", corresponding to the number 0.10. This is $$\frac{1}{2}$$ in binary, implying that $$\nu=\frac{1}{2}$$, as expected for input state "10".

{
"functions": [
{
"name": "main",
"body": [
{
"function": "XGate",
"function_params": {},
"outputs": {
"TARGET": "x_qpe"
}
},
{
"function": "PhaseEstimation",
"function_params": {
"size": 2,
"unitary": "Exponentiation",
"unitary_params": {
"pauli_operator": {
"pauli_list": [
["ZI", -0.125],
["IZ", -0.25],
["II", 0.375]
]
},
"evolution_coefficient": -6.283185307179586
}
},
"inputs": {
"IN": "x_qpe"
}
}
]
}
]
}

from math import pi
from classiq.builtin_functions.exponentiation import PauliOperator
from classiq.builtin_functions import Exponentiation, PhaseEstimation, XGate
from classiq import Model, synthesize, show

model = Model()

x_qpe = model.XGate(params=XGate())
qpe_out = model.PhaseEstimation(
params=PhaseEstimation(
size=2,
unitary_params=Exponentiation(
pauli_operator=PauliOperator(
pauli_list=[
("ZI", -0.125),
("IZ", -0.25),
("II", 0.375),
]
),
evolution_coefficient=-2 * pi,
),
),
in_wires={"IN": x_qpe["TARGET"]},
)
quantum_program = synthesize(model.get_model())
show(quantum_program) ## Using Quantum Phase Estimation with Exponentiation¶

Specify parameters using the ExponentiationSpecification object, which bypasses the parameters of the Exponentiation. See Exponentiation.

PhaseEstimation:

• exponentiation_specification: Optional[ExponentiationSpecification, ExponentiationScaling] takes one of these options:

• ExponentiationSpecification:

• max_depths: Tuple[int, ...] sets the depth of the ExponentiationConstraints directly for each qubit of the phase estimation, starting from the most significant bit.
• scaling: Optional[ExponentiationScaling] provides a rule for determining the depth.
• ExponentiationScaling:

• max_depth: int determines the depth of the most significant bit.
• max_depth_scaling_factor: float provides an exponential growth factor for consecutive qubits.

Inputting exponentiation_specification automatically sets ExponentiationOptimization.MINIMIZE_ERROR.

## Using Custom Functions and Composite Functions¶

Define custom functions or composite functions in the unitary_params argument of PhaseEstimation. Make sure the input and output names are identical.

If using the textual model to provide a custom or composite function, you must define the inputs and outputs in the logic flow as defined in the function.

Define the parameters using the unitary_params argument of the CustomFunction:

• input_decls: ArithmeticIODict
• output_decls: ArithmeticIODict

### Example¶

{
"functions": [
{
"name": "main",
"body": [
{
"function": "PhaseEstimation",
"function_params": {
"unitary": "my_custom_function",
"unitary_params": {
"input_decls": {"custom_input": {"size": 1}},
"output_decls": {"custom_output": {"size": 1}}
},
"size": 2
}
}
]
},
{
"name": "my_custom_function",
"implementations": [
{
"serialized_circuit": "OPENQASM 2.0;\ninclude \"qelib1.inc\";\nqreg q;\nh q;"
}
],
"register_mapping": {
"output_registers": [{"name": "custom_output", "qubits": }],
"input_registers": [{"name": "custom_input", "qubits": }]
}
}
]
}

from classiq import FunctionLibrary, QReg, qfunc
from classiq.builtin_functions import PhaseEstimation
from classiq import Model, synthesize, show

@qfunc
def my_custom(custom_input: QReg) -> QReg:
return 'OPENQASM 2.0;\ninclude "qelib1.inc";\nqreg q;\nh q;\n'

func_library = FunctionLibrary()

qpe_params = PhaseEstimation(
size=2, unitary="my_custom", unitary_params=func_library.get_function("my_custom")
)

model = Model()
model.include_library(func_library)
model.PhaseEstimation(params=qpe_params)

quantum_program = synthesize(model.get_model())
show(quantum_program) A. Yu. Kitaev Barenco et al, Quantum Measurements and the Abelian Stabilizer Problem, (1995). https://doi.org/10.48550/arXiv.quant-ph/9511026