Source code for qiskit.aqua.circuits.phase_estimation_circuit

# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Quantum Phase Estimation Circuit."""

import warnings
import numpy as np

from qiskit import QuantumRegister, QuantumCircuit, ClassicalRegister

from qiskit.aqua import AquaError
from qiskit.aqua.operators import (WeightedPauliOperator,   # pylint: disable=unused-import
                                   suzuki_expansion_slice_pauli_list,
                                   evolution_instruction)


[docs]class PhaseEstimationCircuit: """Quantum Phase Estimation Circuit.""" def __init__( self, operator=None, state_in=None, iqft=None, num_time_slices=1, num_ancillae=1, expansion_mode='trotter', expansion_order=1, evo_time=2 * np.pi, state_in_circuit_factory=None, unitary_circuit_factory=None, shallow_circuit_concat=False, pauli_list=None ): """ Args: operator (WeightedPauliOperator): the hamiltonian Operator object state_in (InitialState): the InitialState component representing the initial quantum state iqft (Union[QuantumCircuit, IQFT]): the Inverse Quantum Fourier Transform as circuit or Aqua component num_time_slices (int): the number of time slices num_ancillae (int): the number of ancillary qubits to use for the measurement expansion_mode (str): the expansion mode (trotter|suzuki) expansion_order (int): the suzuki expansion order evo_time (float): the evolution time state_in_circuit_factory (CircuitFactory): the initial state represented by a CircuitFactory object unitary_circuit_factory (CircuitFactory): the problem unitary represented by a CircuitFactory object shallow_circuit_concat (bool): indicate whether to use shallow (cheap) mode for circuit concatenation pauli_list (list[Pauli]): the flat list of paulis for the operator Raises: AquaError: Missing input """ if (operator is not None and unitary_circuit_factory is not None) or \ (operator is None and unitary_circuit_factory is None): raise AquaError('Please supply either an operator or a unitary circuit ' 'factory but not both.') self._operator = operator if operator is not None: self._pauli_list = operator.reorder_paulis() if pauli_list is None else pauli_list self._unitary_circuit_factory = unitary_circuit_factory self._state_in = state_in self._state_in_circuit_factory = state_in_circuit_factory # cannot check for IQFT type due to circular import if not isinstance(iqft, QuantumCircuit): warnings.warn('Providing a qiskit.aqua.components.iqfts.IQFT module to the ' 'PhaseEstimationCircuit is deprecated as of 0.7.0 ' 'and will be removed no earlier than 3 months after the release. ' 'You should pass a QuantumCircuit instead, see ' 'qiskit.circuit.library.QFT and the .inverse() method.', DeprecationWarning, stacklevel=2) self._iqft = iqft self._num_time_slices = num_time_slices self._num_ancillae = num_ancillae self._expansion_mode = expansion_mode self._expansion_order = expansion_order self._evo_time = evo_time self._shallow_circuit_concat = shallow_circuit_concat self._ancilla_phase_coef = 1 self._state_register = None self._ancillary_register = None self._auxiliary_register = None self._circuit = None
[docs] def construct_circuit( self, state_register=None, ancillary_register=None, auxiliary_register=None, measurement=False, ): """Construct the Phase Estimation circuit Args: state_register (QuantumRegister): the optional register to use for the quantum state ancillary_register (QuantumRegister): the optional register to use for the ancillary measurement qubits auxiliary_register (QuantumRegister): an optional auxiliary quantum register measurement (bool): Boolean flag to indicate if measurement should be included in the circuit. Returns: QuantumCircuit: the QuantumCircuit object for the constructed circuit Raises: RuntimeError: Multiple identity pauli terms are present ValueError: invalid mode """ # pylint: disable=invalid-name if self._circuit is None: if ancillary_register is None: a = QuantumRegister(self._num_ancillae, name='a') else: a = ancillary_register self._ancillary_register = a if state_register is None: if self._operator is not None: q = QuantumRegister(self._operator.num_qubits, name='q') elif self._unitary_circuit_factory is not None: q = QuantumRegister(self._unitary_circuit_factory.num_target_qubits, name='q') else: raise RuntimeError('Missing operator specification.') else: q = state_register self._state_register = q qc = QuantumCircuit(a, q) if auxiliary_register is None: num_aux_qubits, aux = 0, None if self._state_in_circuit_factory is not None: num_aux_qubits = self._state_in_circuit_factory.required_ancillas() if self._unitary_circuit_factory is not None: num_aux_qubits = \ max(num_aux_qubits, self._unitary_circuit_factory.required_ancillas_controlled()) if num_aux_qubits > 0: aux = QuantumRegister(num_aux_qubits, name='aux') qc.add_register(aux) else: aux = auxiliary_register qc.add_register(aux) # initialize state_in if self._state_in is not None: qc.data += self._state_in.construct_circuit('circuit', q).data elif self._state_in_circuit_factory is not None: self._state_in_circuit_factory.build(qc, q, aux) # Put all ancillae in uniform superposition qc.u2(0, np.pi, a) # phase kickbacks via dynamics if self._operator is not None: # check for identify paulis to get its coef for applying # global phase shift on ancillae later num_identities = 0 for p in self._pauli_list: if np.all(np.logical_not(p[1].z)) and np.all(np.logical_not(p[1].x)): num_identities += 1 if num_identities > 1: raise RuntimeError('Multiple identity pauli terms are present.') self._ancilla_phase_coef = p[0].real if isinstance(p[0], complex) else p[0] if len(self._pauli_list) == 1: slice_pauli_list = self._pauli_list else: if self._expansion_mode == 'trotter': slice_pauli_list = self._pauli_list elif self._expansion_mode == 'suzuki': slice_pauli_list = suzuki_expansion_slice_pauli_list( self._pauli_list, 1, self._expansion_order ) else: raise ValueError( 'Unrecognized expansion mode {}.'.format(self._expansion_mode)) for i in range(self._num_ancillae): qc_evolutions_inst = evolution_instruction( slice_pauli_list, -self._evo_time, self._num_time_slices, controlled=True, power=(2 ** i), shallow_slicing=self._shallow_circuit_concat) if self._shallow_circuit_concat: qc_evolutions = QuantumCircuit(q, a) qc_evolutions.append(qc_evolutions_inst, qargs=list(q) + [a[i]]) qc.data += qc_evolutions.data else: qc.append(qc_evolutions_inst, qargs=list(q) + [a[i]]) # global phase shift for the ancilla due to the identity pauli term qc.u1(self._evo_time * self._ancilla_phase_coef * (2 ** i), a[i]) elif self._unitary_circuit_factory is not None: for i in range(self._num_ancillae): self._unitary_circuit_factory.build_controlled_power(qc, q, a[i], 2 ** i, aux) # inverse qft on ancillae if isinstance(self._iqft, QuantumCircuit): # check if QFT has the right size if self._iqft.num_qubits != len(a): try: # try resizing self._iqft.num_qubits = len(a) except AttributeError: raise ValueError('The IQFT cannot be resized and does not have the ' 'required size of {}'.format(len(a))) if hasattr(self._iqft, 'do_swaps'): self._iqft.do_swaps = False qc.append(self._iqft.to_instruction(), a) else: self._iqft.construct_circuit(mode='circuit', qubits=a, circuit=qc, do_swaps=False) if measurement: c_ancilla = ClassicalRegister(self._num_ancillae, name='ca') qc.add_register(c_ancilla) # real hardware can currently not handle operations after measurements, which might # happen if the circuit gets transpiled, hence we're adding a safeguard-barrier qc.barrier() qc.measure(a, c_ancilla) self._circuit = qc return self._circuit
@property def state_register(self): """ returns state register """ return self._state_register @property def ancillary_register(self): """ returns ancillary register """ return self._ancillary_register @property def auxiliary_register(self): """ returns auxiliary register """ return self._auxiliary_register