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. [1].
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:
- Initialize the state
"10"
over two qubits usingXGate
on the first qubit. - Apply a phase estimation on the matrix.
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[0]": "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[0]": 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 theExponentiationConstraints
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[1];\nh q[0];"
}
],
"register_mapping": {
"output_registers": [{"name": "custom_output", "qubits": [0]}],
"input_registers": [{"name": "custom_input", "qubits": [0]}]
}
}
]
}
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[1]) -> QReg[1]:
return 'OPENQASM 2.0;\ninclude "qelib1.inc";\nqreg q[1];\nh q[0];\n'
func_library = FunctionLibrary()
func_library.add_function(my_custom)
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)
References¶
[1] A. Yu. Kitaev Barenco et al, Quantum Measurements and the Abelian Stabilizer Problem, (1995). https://doi.org/10.48550/arXiv.quant-ph/9511026