Phase estimation ================ The :class:`~qdk_chemistry.algorithms.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 :doc:`algorithm design principles <../design/index>`, it takes a state-preparation :class:`~qdk_chemistry.data.Circuit` (from :doc:`StatePreparation `), a :class:`~qdk_chemistry.data.QubitHamiltonian` (from :doc:`QubitMapper ` or a :doc:`model Hamiltonian <../model_hamiltonians>`), a unitary builder (e.g., :doc:`TimeEvolutionBuilder `), a :doc:`ControlledEvolutionCircuitMapper `, and a :doc:`CircuitExecutor ` as input and returns a :class:`~qdk_chemistry.data.QpeResult` containing the measured phase, reconstructed energy, and alias-resolution metadata. Overview -------- Quantum Phase Estimation (:term:`QPE`) is one of the foundational quantum algorithms for chemistry. Given a unitary :math:`U` and an initial state :math:`|\psi\rangle` that has significant overlap with an eigenstate of :math:`U`, :term:`QPE` measures the eigenphase :math:`\phi` such that :math:`U|\psi\rangle = e^{2\pi i \phi}|\psi\rangle`. For chemistry applications the unitary is typically the Hamiltonian time-evolution operator :math:`U = e^{-iHt}`, in which case the energy eigenvalue is recovered as :math:`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 :term:`QPE` approaches, each suited to different hardware constraints: Iterative Quantum Phase Estimation (:term:`IQPE`) Kitaev's single-ancilla algorithm :cite:`Kitaev1995` 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 :cite:`Nielsen-Chuang2010-QPE` that uses a register of :math:`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 :class:`~qdk_chemistry.data.QpeResult` objects with automatic phase-wrapping, energy alias detection, and full :doc:`serialization <../data/serialization>` support. See :doc:`../data/qpe_result` for details on the result data class. .. _qpe-workflow: Typical workflow ~~~~~~~~~~~~~~~~ A complete :term:`QPE` workflow connects several stages of the QDK/Chemistry pipeline. The most common path starts from a molecular system: 1. Prepare a reference :class:`~qdk_chemistry.data.Wavefunction` from a :doc:`multi-configuration calculation ` 2. Generate a state-preparation :class:`~qdk_chemistry.data.Circuit` using :doc:`StatePreparation ` 3. Map the molecular :class:`~qdk_chemistry.data.Hamiltonian` to qubit operators using :doc:`QubitMapper ` 4. Choose a method for constructing the target unitary (currently, QDK/Chemistry provides :doc:`time-evolution builders ` for Hamiltonian simulation) 5. Run phase estimation to obtain the energy eigenvalue Alternatively, phase estimation can be used with :doc:`model Hamiltonians <../model_hamiltonians>` (e.g., Hubbard, Heisenberg, or Ising spin models) or with a user-supplied :class:`~qdk_chemistry.data.Circuit` and :class:`~qdk_chemistry.data.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 :class:`~qdk_chemistry.data.QpeResult` containing the measured phase, energy, alias candidates, and measurement metadata. Input requirements ~~~~~~~~~~~~~~~~~~ The :class:`~qdk_chemistry.algorithms.PhaseEstimation` requires the following inputs: State preparation circuit A :class:`~qdk_chemistry.data.Circuit` that prepares the target quantum state on the system register. This is typically generated by the :doc:`StatePreparation ` algorithm from a :class:`~qdk_chemistry.data.Wavefunction`, but can also be any user-constructed circuit (e.g., a custom initial state for a :doc:`model Hamiltonian <../model_hamiltonians>`). QubitHamiltonian A :class:`~qdk_chemistry.data.QubitHamiltonian` containing the Pauli-string representation of the Hamiltonian. This can be obtained from the :doc:`QubitMapper ` algorithm, constructed from a :doc:`model Hamiltonian <../model_hamiltonians>`, or built directly by the user. Unitary builder An algorithm that constructs the unitary operator :math:`U` whose eigenphase is to be measured. For chemistry applications this is typically a :doc:`TimeEvolutionBuilder ` that approximates :math:`U(t) = e^{-iHt}`. The builder produces a :class:`~qdk_chemistry.data.TimeEvolutionUnitary` which is then converted to a controlled circuit. ControlledEvolutionCircuitMapper Converts a :class:`~qdk_chemistry.data.TimeEvolutionUnitary` into a *controlled* version and synthesises it as an executable :class:`~qdk_chemistry.data.Circuit`. The default implementation (``"pauli_sequence"``) constructs controlled Pauli rotations from a :class:`~qdk_chemistry.data.PauliProductFormulaContainer`. See :doc:`circuit_mapper` for details. CircuitExecutor A backend that executes :class:`~qdk_chemistry.data.Circuit` objects and returns measurement bitstrings as :class:`~qdk_chemistry.data.CircuitExecutorData`. QDK/Chemistry ships native Q# simulators (sparse-state and full-state, with optional :class:`~qdk_chemistry.data.QuantumErrorProfile` noise modelling) and integrates with Qiskit's Aer simulator through the :doc:`plugin system <../plugins>`. See :doc:`circuit_executor` 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. .. rubric:: Creating a phase estimation algorithm .. tab:: Python API .. literalinclude:: ../../../_static/examples/python/phase_estimation.py :language: python :start-after: # start-cell-create :end-before: # end-cell-create .. rubric:: Configuring settings Settings vary by implementation. See `Available implementations`_ below for implementation-specific options. .. tab:: Python API (Iterative) .. literalinclude:: ../../../_static/examples/python/phase_estimation.py :language: python :start-after: # start-cell-configure-iqpe :end-before: # end-cell-configure-iqpe .. tab:: Python API (Standard) .. literalinclude:: ../../../_static/examples/python/phase_estimation.py :language: python :start-after: # start-cell-configure-standard :end-before: # end-cell-configure-standard .. rubric:: Running the calculation Once configured, the :class:`~qdk_chemistry.algorithms.PhaseEstimation` can be executed with all required dependencies: .. tab:: Python API .. literalinclude:: ../../../_static/examples/python/phase_estimation.py :language: python :start-after: # start-cell-run :end-before: # end-cell-run Available implementations ------------------------- QDK/Chemistry's :class:`~qdk_chemistry.algorithms.PhaseEstimation` provides a unified interface for phase estimation methods. You can discover available implementations programmatically: .. tab:: Python API .. literalinclude:: ../../../_static/examples/python/phase_estimation.py :language: python :start-after: # start-cell-list-implementations :end-before: # end-cell-list-implementations .. _iqpe-algorithm: Iterative phase estimation (IQPE) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. rubric:: Factory name: ``"iterative"`` Kitaev's iterative algorithm :cite:`Kitaev1995` 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 :math:`k` (from :math:`0` to :math:`n-1`, where :math:`n` is the total number of bits): 1. Prepare the ancilla in :math:`|+\rangle` 2. Apply the controlled evolution :math:`C\text{-}U^{2^{n-k-1}}` between the ancilla and the system register 3. Apply a phase correction :math:`R_z(-\Phi_k)` based on previously measured bits 4. Measure the ancilla to determine bit :math:`k` The phase feedback is updated using Kitaev's recursion: .. math:: \Phi_{k} = \frac{\Phi_{k+1}}{2} + \frac{\pi \cdot b_k}{2} where :math:`b_k` is the measured bit. Each bit is determined by a majority vote over multiple circuit executions (controlled by ``shots_per_bit``). .. rubric:: Settings .. list-table:: :header-rows: 1 :widths: 25 15 60 * - Setting - Type - Description * - ``num_bits`` - int - Number of phase bits to extract. More bits yield higher energy precision. * - ``evolution_time`` - float - Time parameter :math:`t` in :math:`U = e^{-iHt}`. Determines the energy scale: :math:`E = 2\pi\phi / t`. * - ``shots_per_bit`` - int - Number of circuit executions per bit, used for majority-vote determination. Default is 3. .. _standard-qpe-algorithm: Standard QFT-based phase estimation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. rubric:: Factory name: ``"qiskit_standard"`` The standard :term:`QPE` algorithm :cite:`Nielsen-Chuang2010-QPE` uses a register of :math:`n` ancilla qubits to extract all phase bits simultaneously. The circuit structure consists of: 1. Initialize :math:`n` ancilla qubits in :math:`|+\rangle` 2. For each ancilla qubit :math:`j \in \{0, \ldots, n-1\}`, apply the controlled evolution :math:`C\text{-}U^{2^j}` 3. Apply an inverse Quantum Fourier Transform (iQFT) to the ancilla register 4. Measure all ancilla qubits The phase is extracted from the dominant bitstring in the measurement results. .. rubric:: Settings .. list-table:: :header-rows: 1 :widths: 25 15 60 * - Setting - Type - Description * - ``num_bits`` - int - Number of ancilla qubits (phase register size). More bits yield higher energy precision. * - ``evolution_time`` - float - Time parameter :math:`t` in :math:`U = e^{-iHt}`. Determines the energy scale. * - ``shots`` - int - Total measurement shots for the full circuit. Default is 3. * - ``qft_do_swaps`` - 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 :math:`\phi \in [0, 1)`, the reconstructed energy :math:`E = 2\pi\phi / t` is only unique modulo :math:`2\pi / t`. This means several energy values — called *aliases* — can produce the same measured phase. QDK/Chemistry handles this automatically in the :class:`~qdk_chemistry.data.QpeResult` data class: - ``branching`` contains the full list of alias energy candidates :math:`E + k \cdot 2\pi/t` for :math:`k \in \{-2, -1, 0, 1, 2\}` by default - If a ``reference_energy`` is provided (e.g., the :term:`CASCI` energy), the alias closest to the reference is selected as ``resolved_energy`` - ``canonical_phase_fraction`` and ``canonical_phase_angle`` reflect the alias-resolved phase See :doc:`../data/qpe_result` for the full data class documentation. Related classes --------------- - :class:`~qdk_chemistry.data.QpeResult`: Output data class containing phase, energy, and alias information - :class:`~qdk_chemistry.data.QubitHamiltonian`: Input qubit Hamiltonian - :class:`~qdk_chemistry.data.Circuit`: State-preparation circuit from :doc:`StatePreparation ` - :class:`~qdk_chemistry.data.TimeEvolutionUnitary`: Output of :doc:`TimeEvolutionBuilder ` - :class:`~qdk_chemistry.data.CircuitExecutorData`: Measurement results from :doc:`CircuitExecutor ` - :class:`~qdk_chemistry.data.QuantumErrorProfile`: Noise model for noisy simulation Further reading --------------- - The above examples can be downloaded as a complete `Python <../../../_static/examples/python/phase_estimation.py>`_ script. - :doc:`TimeEvolutionBuilder `: Hamiltonian simulation via Trotter-Suzuki decomposition - :doc:`CircuitExecutor `: Quantum circuit execution backends - :doc:`ControlledEvolutionCircuitMapper `: Controlled-unitary circuit synthesis - :doc:`StatePreparation `: Load wavefunctions onto qubits as quantum circuits - :doc:`QubitMapper `: Map fermionic Hamiltonians to qubit operators - :doc:`QpeResult <../data/qpe_result>`: Phase estimation result data class - See the ``examples/qpe_stretched_n2.ipynb`` notebook for a complete end-to-end :term:`QPE` workflow - :doc:`Settings `: Configuration settings for algorithms - :doc:`Factory Pattern `: Understanding algorithm creation