Source code for mitiq.benchmarks.qpe_circuits

# Copyright (C) Unitary Fund
# This source code is licensed under the GPL license (v3) found in the
# LICENSE file in the root directory of this source tree.

"""Functions to create a QPE circuit."""

from typing import Optional

import cirq

from mitiq import QPROGRAM
from mitiq.interface import convert_from_mitiq

[docs]def generate_qpe_circuit( evalue_reg: int, input_gate: cirq.Gate = cirq.T, return_type: Optional[str] = None, ) -> QPROGRAM: """Returns a circuit to create a quantum phase estimation (QPE) circuit as defined in The unitary to estimate the phase of corresponds to a single-qubit gate (``input_gate``). The IQFT circuit defined in this method is taken from taken from Sec 7.7.4 of :cite:`Wong_2022`. The notation for eigenvalue register and eigenstate register used to define this function also follows from :cite:`Wong_2022`. Args: evalue_reg : Number of qubits in the eigenvalue register. The qubits in this variable are used to estimate the phase. input_gate : The unitary to estimate the phase of as a single-qubit Cirq gate. Default gate used here is `cirq.T`. return_type: Return type of the output circuit. Returns: A Quantum Phase Estimation circuit. """ if evalue_reg <= 0: raise ValueError( "{} is invalid for the number of eigenvalue reg qubits. ", evalue_reg, ) num_qubits_for_gate = input_gate.num_qubits() if num_qubits_for_gate > 1: raise ValueError("This QPE method only works for 1-qubit gates.") if evalue_reg == num_qubits_for_gate: raise ValueError( "The eigenvalue reg must be larger than the eigenstate reg." ) total_num_qubits = evalue_reg + num_qubits_for_gate qreg = cirq.LineQubit.range(total_num_qubits) circuit = cirq.Circuit() # QFT circuit # apply hadamard and controlled unitary to the qubits in the eigenvalue reg hadamard_circuit = cirq.Circuit() for i in range(evalue_reg): hadamard_circuit.append(cirq.H(qreg[i])) circuit = circuit + hadamard_circuit for i in range(total_num_qubits - 1)[::-1]: circuit.append( [input_gate(qreg[-1]).controlled_by(qreg[i])] * (2 ** (evalue_reg - 1 - i)) ) # IQFT of the eigenvalue register # swap the qubits in the eigenvalue register for i in range(int(evalue_reg / 2)): circuit.append( cirq.SWAP(qreg[i], qreg[evalue_reg - 1 - i]), strategy=cirq.InsertStrategy.NEW, ) # apply inverse of hadamard followed by controlled unitary circuit.append(cirq.H(qreg[0]), strategy=cirq.InsertStrategy.NEW) for i in range(1, evalue_reg): for j in range(evalue_reg): if j < i: circuit.append( cirq.inverse(input_gate(qreg[i]).controlled_by(qreg[j])), strategy=cirq.InsertStrategy.NEW, ) circuit.append( cirq.H(qreg[i]), strategy=cirq.InsertStrategy.NEW, ) return_type = "cirq" if not return_type else return_type return convert_from_mitiq(circuit, return_type)