Controlled evolution circuit mapper

The ControlledEvolutionCircuitMapper algorithm in QDK/Chemistry converts a TimeEvolutionUnitary into a controlled quantum circuit. Following QDK/Chemistry’s algorithm design principles, it takes a ControlledTimeEvolutionUnitary as input and produces a Circuit as output.

Overview

Controlled unitaries — operations of the form \(C\text{-}U\) that apply \(U\) to a target register conditioned on the state of a control qubit — are a building block in many quantum algorithms. Mathematically, for a single control qubit the controlled unitary acts as:

\[C\text{-}U \;=\; |0\rangle\langle 0| \otimes I \;+\; |1\rangle\langle 1| \otimes U\]

That is, the target register is left unchanged when the control is \(|0\rangle\) and \(U\) is applied when the control is \(|1\rangle\).

The ControlledEvolutionCircuitMapper synthesises these controlled operations from the abstract TimeEvolutionUnitary representation produced by a TimeEvolutionBuilder. This is a core component of algorithms such as PhaseEstimation, which requires repeated controlled applications \(C\text{-}U^{2^k}\).

The mapper takes two inputs:

  1. A ControlledTimeEvolutionUnitary — which pairs a TimeEvolutionUnitary with the control qubit indices

  2. An optional power parameter that controls how many times the unitary is repeated (\(U^{\text{power}}\))

The resulting Circuit implements the controlled unitary and can be executed by a CircuitExecutor.

Using the ControlledEvolutionCircuitMapper

Note

This algorithm is currently available only in the Python API.

This section demonstrates how to create, configure, and run the circuit mapper.

Input requirements

The ControlledEvolutionCircuitMapper requires:

ControlledTimeEvolutionUnitary

A ControlledTimeEvolutionUnitary wrapping a TimeEvolutionUnitary and specifying which qubits serve as controls.

Creating a mapper

from qdk_chemistry.algorithms import create

# Create the default mapper (pauli_sequence)
mapper = create("controlled_evolution_circuit_mapper")

Configuring settings

# Configure the power of the controlled unitary
mapper = create("controlled_evolution_circuit_mapper", "pauli_sequence")
mapper.settings().set("power", 4)

Running the mapper

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 and qubit mapping
hamiltonian_constructor = create("hamiltonian_constructor")
hamiltonian = hamiltonian_constructor.run(wfn_scf.get_orbitals())
qubit_mapper = create("qubit_mapper", encoding="jordan-wigner")
qubit_ham = qubit_mapper.run(hamiltonian)

# 4. Build time evolution unitary
trotter = create("time_evolution_builder", "trotter", order=2)
evolution = trotter.run(qubit_ham, time=0.1)

# 5. Create a controlled version and map to a circuit
from qdk_chemistry.data import ControlledTimeEvolutionUnitary

controlled = ControlledTimeEvolutionUnitary(evolution, control_indices=[0])
mapper = create("controlled_evolution_circuit_mapper", "pauli_sequence")
circuit = mapper.run(controlled)
print("Controlled evolution circuit generated")

Available implementations

You can discover available implementations programmatically:

from qdk_chemistry.algorithms import registry

# List all registered controlled evolution circuit mapper implementations
implementations = registry.available("controlled_evolution_circuit_mapper")
print(implementations)  # e.g. ['pauli_sequence']

Pauli sequence mapper

Factory name: "pauli_sequence" (default)

Given a time-evolution unitary expressed as a PauliProductFormulaContainer — a sequence of exponentiated Pauli terms \(e^{-i\theta_j P_j}\) — this mapper constructs a controlled version by:

  1. Rotating each Pauli operator \(P_j\) into the Z basis

  2. Entangling the target qubits with a CNOT ladder

  3. Applying a controlled \(R_z(2\theta_j)\) rotation from the control qubit

  4. Uncomputing the basis rotations and entangling operations

Note

The current implementation supports a single control qubit.

Settings

Setting

Type

Description

power

int

Number of times the unitary is repeated (\(U^{\text{power}}\)). Default is 1.

Further reading