Phase estimation
The PhaseEstimation algorithm in QDK/Chemistry extracts eigenvalues from a quantum state by measuring the phase accumulated under repeated application of a unitary operator.
Following QDK/Chemistry’s algorithm design principles, it takes a state-preparation Circuit (from StatePreparation), a QubitHamiltonian (from QubitMapper or a model Hamiltonian), a unitary builder (e.g., TimeEvolutionBuilder), a ControlledEvolutionCircuitMapper, and a CircuitExecutor as input and returns a QpeResult containing the measured phase, reconstructed energy, and alias-resolution metadata.
Overview
Quantum Phase Estimation (QPE) is one of the foundational quantum algorithms for chemistry. Given a unitary \(U\) and an initial state \(|\psi\rangle\) that has significant overlap with an eigenstate of \(U\), QPE measures the eigenphase \(\phi\) such that \(U|\psi\rangle = e^{2\pi i \phi}|\psi\rangle\). For chemistry applications the unitary is typically the Hamiltonian time-evolution operator \(U = e^{-iHt}\), in which case the energy eigenvalue is recovered as \(E = 2\pi\phi / t\). However, the algorithm itself is agnostic to how the unitary is constructed — any operator whose eigenvalues encode the quantity of interest can be used.
QDK/Chemistry provides two QPE approaches, each suited to different hardware constraints:
- Iterative Quantum Phase Estimation (IQPE)
Kitaev’s single-ancilla algorithm [Kit95] that extracts phase bits one at a time, from most significant to least significant, using adaptive feedback corrections between iterations. This approach minimizes ancilla requirements and is particularly suited to near-term hardware.
- Standard QFT-based Quantum Phase Estimation
The textbook multi-ancilla approach [NC10] that uses a register of \(n\) ancilla qubits and an inverse Quantum Fourier Transform to extract all phase bits simultaneously. This approach achieves all precision bits in a single circuit execution but requires more ancilla qubits and longer circuit depth.
Both implementations share the same interface and produce QpeResult objects with automatic phase-wrapping, energy alias detection, and full serialization support.
See QpeResult for details on the result data class.
Typical workflow
A complete QPE workflow connects several stages of the QDK/Chemistry pipeline. The most common path starts from a molecular system:
Prepare a reference
Wavefunctionfrom a multi-configuration calculationGenerate a state-preparation
Circuitusing StatePreparationMap the molecular
Hamiltonianto qubit operators using QubitMapperChoose a method for constructing the target unitary (currently, QDK/Chemistry provides time-evolution builders for Hamiltonian simulation)
Run phase estimation to obtain the energy eigenvalue
Alternatively, phase estimation can be used with model Hamiltonians (e.g., Hubbard, Heisenberg, or Ising spin models) or with a user-supplied Circuit and QubitHamiltonian directly — the full molecular-structure pipeline is not required.
Using the PhaseEstimation
Note
This algorithm is currently available only in the Python API.
This section demonstrates how to create, configure, and run a phase estimation calculation.
The run method returns a QpeResult containing the measured phase, energy, alias candidates, and measurement metadata.
Input requirements
The PhaseEstimation requires the following inputs:
- State preparation circuit
A
Circuitthat prepares the target quantum state on the system register. This is typically generated by the StatePreparation algorithm from aWavefunction, but can also be any user-constructed circuit (e.g., a custom initial state for a model Hamiltonian).- QubitHamiltonian
A
QubitHamiltoniancontaining the Pauli-string representation of the Hamiltonian. This can be obtained from the QubitMapper algorithm, constructed from a model Hamiltonian, or built directly by the user.- Unitary builder
An algorithm that constructs the unitary operator \(U\) whose eigenphase is to be measured. For chemistry applications this is typically a TimeEvolutionBuilder that approximates \(U(t) = e^{-iHt}\). The builder produces a
TimeEvolutionUnitarywhich is then converted to a controlled circuit.- ControlledEvolutionCircuitMapper
Converts a
TimeEvolutionUnitaryinto a controlled version and synthesises it as an executableCircuit. The default implementation ("pauli_sequence") constructs controlled Pauli rotations from aPauliProductFormulaContainer. See Controlled evolution circuit mapper for details.- CircuitExecutor
A backend that executes
Circuitobjects and returns measurement bitstrings asCircuitExecutorData. QDK/Chemistry ships native Q# simulators (sparse-state and full-state, with optionalQuantumErrorProfilenoise modelling) and integrates with Qiskit’s Aer simulator through the plugin system. See Circuit execution for details.
Note
The state preparation circuit and qubit Hamiltonian must be compatible — they should use the same qubit encoding and be derived from the same underlying system.
Creating a phase estimation algorithm
from qdk_chemistry.algorithms import create
# Create the default (iterative) phase estimation algorithm
iqpe = create("phase_estimation", "iterative")
# Or create the standard QFT-based variant (requires Qiskit)
qpe = create("phase_estimation", "qiskit_standard")
Configuring settings
Settings vary by implementation. See Available implementations below for implementation-specific options.
# Configure iterative phase estimation
iqpe = create("phase_estimation", "iterative")
iqpe.settings().set("num_bits", 10)
iqpe.settings().set("evolution_time", 0.1)
iqpe.settings().set("shots_per_bit", 10)
# Configure standard QFT-based phase estimation
qpe = create("phase_estimation", "qiskit_standard")
qpe.settings().set("num_bits", 10)
qpe.settings().set("evolution_time", 0.1)
qpe.settings().set("shots", 100)
qpe.settings().set("qft_do_swaps", True)
Running the calculation
Once configured, the PhaseEstimation can be executed with all required dependencies:
import numpy as np
from qdk_chemistry.algorithms import create
from qdk_chemistry.data import Structure
# 1. Setup molecule
coords = np.array([[0.0, 0.0, 0.0], [0.0, 0.0, 1.4]])
symbols = ["H", "H"]
structure = Structure(coords, symbols=symbols)
# 2. SCF
scf_solver = create("scf_solver")
E_scf, wfn_scf = scf_solver.run(
structure, charge=0, spin_multiplicity=1, basis_or_guess="sto-3g"
)
# 3. Hamiltonian construction
hamiltonian_constructor = create("hamiltonian_constructor")
hamiltonian = hamiltonian_constructor.run(wfn_scf.get_orbitals())
# 4. Multi-configuration calculation (reference state)
cas_solver = create("multi_configuration_calculator")
E_cas, wfn_cas = cas_solver.run(hamiltonian, 1, 1)
# 5. Qubit mapping
qubit_mapper = create("qubit_mapper", encoding="jordan-wigner")
qubit_ham = qubit_mapper.run(hamiltonian)
# 6. State preparation
state_prep = create("state_prep", "sparse_isometry_gf2x")
circuit = state_prep.run(wfn_cas)
# 7. Create QPE dependencies
evolution_builder = create("time_evolution_builder", "trotter", order=2)
circuit_mapper = create("controlled_evolution_circuit_mapper", "pauli_sequence")
circuit_executor = create("circuit_executor", "qiskit_aer_simulator", seed=42)
# 8. Create and run IQPE
iqpe = create(
"phase_estimation", "iterative", num_bits=10, evolution_time=0.1, shots_per_bit=10
)
result = iqpe.run(
state_preparation=circuit,
qubit_hamiltonian=qubit_ham,
evolution_builder=evolution_builder,
circuit_mapper=circuit_mapper,
circuit_executor=circuit_executor,
)
# 9. Inspect results
print(result.get_summary())
Available implementations
QDK/Chemistry’s PhaseEstimation provides a unified interface for phase estimation methods.
You can discover available implementations programmatically:
from qdk_chemistry.algorithms import registry
# List all registered phase estimation implementations
implementations = registry.available("phase_estimation")
print(implementations) # e.g. ['iterative', 'qiskit_standard']
Iterative phase estimation (IQPE)
Factory name: "iterative"
Kitaev’s iterative algorithm [Kit95] uses a single ancilla qubit to extract phase bits sequentially, from the most significant bit (MSB) to the least significant bit (LSB). At each iteration \(k\) (from \(0\) to \(n-1\), where \(n\) is the total number of bits):
Prepare the ancilla in \(|+\rangle\)
Apply the controlled evolution \(C\text{-}U^{2^{n-k-1}}\) between the ancilla and the system register
Apply a phase correction \(R_z(-\Phi_k)\) based on previously measured bits
Measure the ancilla to determine bit \(k\)
The phase feedback is updated using Kitaev’s recursion:
where \(b_k\) is the measured bit.
Each bit is determined by a majority vote over multiple circuit executions (controlled by shots_per_bit).
Settings
Setting |
Type |
Description |
|---|---|---|
|
int |
Number of phase bits to extract. More bits yield higher energy precision. |
|
float |
Time parameter \(t\) in \(U = e^{-iHt}\). Determines the energy scale: \(E = 2\pi\phi / t\). |
|
int |
Number of circuit executions per bit, used for majority-vote determination. Default is 3. |
Standard QFT-based phase estimation
Factory name: "qiskit_standard"
The standard QPE algorithm [NC10] uses a register of \(n\) ancilla qubits to extract all phase bits simultaneously. The circuit structure consists of:
Initialize \(n\) ancilla qubits in \(|+\rangle\)
For each ancilla qubit \(j \in \{0, \ldots, n-1\}\), apply the controlled evolution \(C\text{-}U^{2^j}\)
Apply an inverse Quantum Fourier Transform (iQFT) to the ancilla register
Measure all ancilla qubits
The phase is extracted from the dominant bitstring in the measurement results.
Settings
Setting |
Type |
Description |
|---|---|---|
|
int |
Number of ancilla qubits (phase register size). More bits yield higher energy precision. |
|
float |
Time parameter \(t\) in \(U = e^{-iHt}\). Determines the energy scale. |
|
int |
Total measurement shots for the full circuit. Default is 3. |
|
bool |
Whether to include the final swap layer in the inverse QFT. Default is True. |
Phase aliasing and energy resolution
Because phase estimation measures a phase \(\phi \in [0, 1)\), the reconstructed energy \(E = 2\pi\phi / t\) is only unique modulo \(2\pi / t\). This means several energy values — called aliases — can produce the same measured phase.
QDK/Chemistry handles this automatically in the QpeResult data class:
branchingcontains the full list of alias energy candidates \(E + k \cdot 2\pi/t\) for \(k \in \{-2, -1, 0, 1, 2\}\) by defaultIf a
reference_energyis provided (e.g., the CASCI energy), the alias closest to the reference is selected asresolved_energycanonical_phase_fractionandcanonical_phase_anglereflect the alias-resolved phase
See QpeResult for the full data class documentation.
Further reading
The above examples can be downloaded as a complete Python script.
TimeEvolutionBuilder: Hamiltonian simulation via Trotter-Suzuki decomposition
CircuitExecutor: Quantum circuit execution backends
ControlledEvolutionCircuitMapper: Controlled-unitary circuit synthesis
StatePreparation: Load wavefunctions onto qubits as quantum circuits
QubitMapper: Map fermionic Hamiltonians to qubit operators
QpeResult: Phase estimation result data class
See the
examples/qpe_stretched_n2.ipynbnotebook for a complete end-to-end QPE workflowSettings: Configuration settings for algorithms
Factory Pattern: Understanding algorithm creation