Energy estimation

The EnergyEstimator algorithm in QDK/Chemistry estimates the energy of a quantum state by measuring expectation values of Pauli operators. Following QDK/Chemistry’s algorithm design principles, it takes an OpenQASM circuit (from StatePreparation) and a QubitHamiltonian (from QubitMapper) as input and returns energy expectation values with statistical uncertainty.

Overview

The EnergyEstimator evaluates the expectation value of a QubitHamiltonian with respect to a given quantum circuit that loads a wavefunction onto qubits. It takes a Circuit object and a target qubit Hamiltonian and automatically generates the corresponding measurement circuits. These circuits are executed on a selected backend simulator with the user-specified number of shots, and the resulting bitstring statistics are used to calculate per-term expectation values and the total energy.

The algorithm supports:

Multiple simulator backends

QDK’s native Q# simulator or Qiskit’s Aer simulator

Noise modeling

Depolarizing noise, bit flip noise, Pauli noise, phase flip noise, and qubit loss simulation

Grouped measurements

Efficient measurement of commuting Pauli terms in a single circuit execution

A typical workflow connects StatePreparation (which loads the wavefunction onto qubits) with EnergyEstimator (which measures the energy):

  1. Prepare a Wavefunction from a multi-configuration calculation

  2. Generate an OpenQASM circuit using StatePreparation

  3. Map the Hamiltonian to qubit operators using QubitMapper

  4. Estimate the energy using EnergyEstimator

Using the EnergyEstimator

Note

This algorithm is currently available only in the Python API.

This section demonstrates how to create, configure, and run an energy estimation. The run method returns an energy expectation value with variance and the raw measurement data.

Input requirements

The EnergyEstimator requires the following inputs:

Circuit

A quantum circuit that prepares the target quantum state. This is typically generated by the StatePreparation algorithm from a Wavefunction.

QubitHamiltonian

A QubitHamiltonian instance containing the Pauli-string representation of the electronic Hamiltonian. This is obtained from the QubitMapper algorithm.

Circuit execution

A backend to execute the measurement circuits. Supported backends include QDK’s native Q# simulator and Qiskit’s Aer simulator.

Number of shots

The number of measurement repetitions to perform for statistical sampling. More shots reduce statistical uncertainty but increase computational cost.

Note

The circuit and Hamiltonian must be compatible—they should use the same qubit encoding and be derived from the same underlying molecular system. The estimator automatically generates measurement circuits for each Pauli term in the Hamiltonian and performs the circuit sampling internally.

Creating an estimator

import numpy as np
from qdk_chemistry.algorithms import create
from qdk_chemistry.data import Circuit, QuantumErrorProfile, QubitHamiltonian

# Create energy estimator using Qsharp simulator as backend
qdk_estimator = create("energy_estimator", "qdk")

Configuring settings and running

Settings vary by implementation. The QDK backend supports noise models and qubit loss, while the Qiskit backend supports custom Aer noise models.

# Define a simple quantum circuit in QASM and a qubit Hamiltonian
circuit = Circuit(
    qasm="""
    include "stdgates.inc";
    qubit[2] q;
    rz(pi) q[0];
    x q[0];
    cx q[0], q[1];
    """
)
qubit_hamiltonian = QubitHamiltonian(["ZZ"], np.array([1.0]))

# Run energy estimation using Qsharp simulator without noise
circuit_executor = create("circuit_executor", "qdk_sparse_state_simulator")
energy_expectation_results, measurement_data = qdk_estimator.run(
    circuit, qubit_hamiltonian, circuit_executor, total_shots=1000
)
print(
    "Energy expectation value from noiseless QDK Simulator: "
    f"{energy_expectation_results.energy_expectation_value}"
)

# Create energy estimator using Qsharp simulator with depolarizing noise
noise_model = QuantumErrorProfile(
    name="noise model",
    description="Noise model for QDK full state simulator",
    errors={
        "rz": {
            "type": "depolarizing_error",
            "rate": 0.005,
            "num_qubits": 1,
        },
        "h": {
            "type": "depolarizing_error",
            "rate": 0.005,
            "num_qubits": 1,
        },
        "s": {
            "type": "depolarizing_error",
            "rate": 0.005,
            "num_qubits": 1,
        },
        "cx": {
            "type": "depolarizing_error",
            "rate": 0.007,
            "num_qubits": 2,
        },
    },
)
circuit_executor = create("circuit_executor", "qdk_full_state_simulator", type="cpu")
qdk_estimator = create("energy_estimator", "qdk")
energy_expectation_results, measurement_data = qdk_estimator.run(
    circuit,
    qubit_hamiltonian,
    circuit_executor,
    total_shots=1000,
    noise_model=noise_model,
)
print(
    "Energy expectation value from QDK Simulator with depolarizing noise: "
    f"{energy_expectation_results.energy_expectation_value}"
)
# Run energy estimation using Qiskit Aer simulator without noise
qiskit_aer_simulator = create("circuit_executor", "qiskit_aer_simulator")
energy_expectation_results, measurement_data = qdk_estimator.run(
    circuit, qubit_hamiltonian, qiskit_aer_simulator, total_shots=1000
)
print(
    f"Energy expectation value from Qiskit Aer Simulator: {energy_expectation_results.energy_expectation_value}"
)

# Create energy estimator using Qiskit Aer simulator with noise model

noise_model = QuantumErrorProfile(
    name="noise model",
    description="Noise model for Qiskit Aer simulator",
    errors={
        "rz": {
            "type": "depolarizing_error",
            "rate": 0.005,
            "num_qubits": 1,
        },
        "sx": {
            "type": "depolarizing_error",
            "rate": 0.005,
            "num_qubits": 1,
        },
        "cx": {
            "type": "depolarizing_error",
            "rate": 0.007,
            "num_qubits": 2,
        },
    },
)
energy_expectation_results, measurement_data = qdk_estimator.run(
    circuit,
    qubit_hamiltonian,
    qiskit_aer_simulator,
    total_shots=1000,
    noise_model=noise_model,
)
print(
    "Energy expectation value from Qiskit Aer Simulator with noise: "
    f"{energy_expectation_results.energy_expectation_value}"
)

Available implementations

QDK/Chemistry’s EnergyEstimator provides a unified interface for quantum circuit simulation and energy measurement. You can discover available implementations programmatically:

from qdk_chemistry.algorithms import registry

print(registry.available("energy_estimator"))
# ['qdk']
print(registry.available("circuit_executor"))
# ['qdk_full_state_simulator', 'qdk_sparse_state_simulator', 'qiskit_aer_simulator']

QDK energy estimator

Factory name: "qdk"

Native QDK/Chemistry implementation of energy estimator. Supports various simulator backends and noise models for realistic quantum hardware simulation.

Run parameters

Parameter

Type

Description

circuit

Circuit

Quantum circuit that prepares the target quantum state

qubit_hamiltonian

QubitHamiltonian

Qubit Hamiltonian to measure

circuit_executor

CircuitExecutor

Backend to execute the measurement circuits

total_shots

int

Total number of measurement shots

noise_model

QuantumErrorProfile | None

Noise model to apply during circuit execution

Further reading

  • The above examples can be downloaded as a complete Python script.

  • StatePreparation: Load wavefunctions onto qubits as quantum circuits

  • QubitMapper: Map fermionic Hamiltonians to qubit operators

  • See the examples/state_prep_energy.ipynb notebook for an end-to-end workflow demonstration

  • Settings: Configuration settings for algorithms

  • Factory Pattern: Understanding algorithm creation