def construct_circuit(self, mode, register=None): """ Construct the eigenvalues estimation using the PhaseEstimationCircuit Args: mode (str): consctruction mode, 'matrix' not supported register (QuantumRegister): the register to use for the quantum state Returns: the QuantumCircuit object for the constructed circuit """ if mode == 'matrix': raise ValueError( 'QPE is only possible as a circuit not as a matrix.') pe = PhaseEstimationCircuit(operator=self._operator, state_in=None, iqft=self._iqft, num_time_slices=self._num_time_slices, num_ancillae=self._num_ancillae, expansion_mode=self._expansion_mode, expansion_order=self._expansion_order, evo_time=self._evo_time) a = QuantumRegister(self._num_ancillae) q = register qc = pe.construct_circuit(state_register=q, ancillary_register=a) # handle negative eigenvalues if self._negative_evals: self._handle_negative_evals(qc, a) self._circuit = qc self._output_register = a self._input_register = q return self._circuit
def construct_circuit(self, measurement: bool = False) -> QuantumCircuit: """Construct the Amplitude Estimation quantum circuit. Args: measurement: Boolean flag to indicate if measurements should be included in the circuit. Returns: The QuantumCircuit object for the constructed circuit. """ if self.state_preparation is None: # circuit factories # ignore deprecation warnings from getter, user has already been warned when # the a_factory has been passed warnings.filterwarnings('ignore', category=DeprecationWarning) q_factory = self.q_factory warnings.filterwarnings('always', category=DeprecationWarning) iqft = QFT(self._m, do_swaps=False, inverse=True).reverse_bits() \ if self._iqft is None else self._iqft pec = PhaseEstimationCircuit( iqft=iqft, num_ancillae=self._m, state_in_circuit_factory=self._a_factory, unitary_circuit_factory=q_factory) self._circuit = pec.construct_circuit(measurement=measurement) else: if self._pec is not None: pec = self._pec else: from qiskit.circuit.library import PhaseEstimation pec = PhaseEstimation(self._m, self.grover_operator, iqft=self._iqft) # mypy thinks self.circuit is None even after explicitly being set to QuantumCircuit self._circuit = QuantumCircuit(*pec.qregs) self._circuit.compose( self.state_preparation, # type: ignore list( range(self._m, self._m + self.state_preparation.num_qubits)), inplace=True) self._circuit.compose(pec, inplace=True) # type: ignore if measurement: cr = ClassicalRegister(self._m) self._circuit.add_register(cr) # type: ignore self._circuit.measure(list(range(self._m)), list(range(self._m))) # type: ignore return self._circuit
def construct_circuit(self): """ Construct the Amplitude Estimation quantum circuit. Returns: the QuantumCircuit object for the constructed circuit """ pec = PhaseEstimationCircuit( iqft=self._iqft, num_ancillae=self._m, state_in_circuit_factory=self.a_factory, unitary_circuit_factory=self.q_factory ) self._circuit = pec.construct_circuit() return self._circuit
def construct_circuit(self, measurement: bool = False) -> QuantumCircuit: """Construct the Amplitude Estimation quantum circuit. Args: measurement: Boolean flag to indicate if measurements should be included in the circuit. Returns: The QuantumCircuit object for the constructed circuit. """ pec = PhaseEstimationCircuit(iqft=self._iqft, num_ancillae=self._m, state_in_circuit_factory=self.a_factory, unitary_circuit_factory=self.q_factory) self._circuit = pec.construct_circuit(measurement=measurement) return self._circuit
class QPE(QuantumAlgorithm): """The Quantum Phase Estimation algorithm.""" PROP_NUM_TIME_SLICES = 'num_time_slices' PROP_EXPANSION_MODE = 'expansion_mode' PROP_EXPANSION_ORDER = 'expansion_order' PROP_NUM_ANCILLAE = 'num_ancillae' CONFIGURATION = { 'name': 'QPE', 'description': 'Quantum Phase Estimation for Quantum Systems', 'input_schema': { '$schema': 'http://json-schema.org/draft-07/schema#', 'id': 'qpe_schema', 'type': 'object', 'properties': { PROP_NUM_TIME_SLICES: { 'type': 'integer', 'default': 1, 'minimum': 1 }, PROP_EXPANSION_MODE: { 'type': 'string', 'default': 'trotter', 'enum': ['suzuki', 'trotter'] }, PROP_EXPANSION_ORDER: { 'type': 'integer', 'default': 1, 'minimum': 1 }, PROP_NUM_ANCILLAE: { 'type': 'integer', 'default': 1, 'minimum': 1 } }, 'additionalProperties': False }, 'problems': ['energy'], 'depends': [ { 'pluggable_type': 'initial_state', 'default': { 'name': 'ZERO' }, }, { 'pluggable_type': 'iqft', 'default': { 'name': 'STANDARD', }, }, ], } def __init__(self, operator, state_in, iqft, num_time_slices=1, num_ancillae=1, expansion_mode='trotter', expansion_order=1, shallow_circuit_concat=False): """ Constructor. Args: operator (BaseOperator): the hamiltonian Operator object state_in (InitialState): the InitialState pluggable component representing the initial quantum state iqft (IQFT): the Inverse Quantum Fourier Transform pluggable 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 shallow_circuit_concat (bool): indicate whether to use shallow (cheap) mode for circuit concatenation """ self.validate(locals()) super().__init__() self._operator = op_converter.to_weighted_pauli_operator(operator) self._num_ancillae = num_ancillae self._ret = {} self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=state_in, iqft=iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat, pauli_list=self._pauli_list) self._binary_fractions = [1 / 2**p for p in range(1, num_ancillae + 1)] @classmethod def init_params(cls, params, algo_input): """ Initialize via parameters dictionary and algorithm input instance. Args: params (dict): parameters dictionary algo_input (EnergyInput): instance Returns: QPE: instance of this class Raises: AquaError: EnergyInput instance is required. """ if algo_input is None: raise AquaError("EnergyInput instance is required.") operator = algo_input.qubit_op qpe_params = params.get(Pluggable.SECTION_KEY_ALGORITHM) num_time_slices = qpe_params.get(QPE.PROP_NUM_TIME_SLICES) expansion_mode = qpe_params.get(QPE.PROP_EXPANSION_MODE) expansion_order = qpe_params.get(QPE.PROP_EXPANSION_ORDER) num_ancillae = qpe_params.get(QPE.PROP_NUM_ANCILLAE) # Set up initial state, we need to add computed num qubits to params init_state_params = params.get(Pluggable.SECTION_KEY_INITIAL_STATE) init_state_params['num_qubits'] = operator.num_qubits init_state = get_pluggable_class( PluggableType.INITIAL_STATE, init_state_params['name']).init_params(params) # Set up iqft, we need to add num qubits to params which is our num_ancillae bits here iqft_params = params.get(Pluggable.SECTION_KEY_IQFT) iqft_params['num_qubits'] = num_ancillae iqft = get_pluggable_class(PluggableType.IQFT, iqft_params['name']).init_params(params) return cls(operator, init_state, iqft, num_time_slices, num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order) def construct_circuit(self, measurement=False): """ Construct circuit. Args: measurement (bool): Boolean flag to indicate if measurement should be included in the circuit. Returns: QuantumCircuit: quantum circuit. """ qc = self._phase_estimation_circuit.construct_circuit( measurement=measurement) return qc def _compute_energy(self): if self._quantum_instance.is_statevector: qc = self.construct_circuit(measurement=False) result = self._quantum_instance.execute(qc) complete_state_vec = result.get_statevector(qc) ancilla_density_mat = get_subsystem_density_matrix( complete_state_vec, range(self._num_ancillae, self._num_ancillae + self._operator.num_qubits)) ancilla_density_mat_diag = np.diag(ancilla_density_mat) max_amplitude = \ max(ancilla_density_mat_diag.min(), ancilla_density_mat_diag.max(), key=abs) max_amplitude_idx = np.where( ancilla_density_mat_diag == max_amplitude)[0][0] top_measurement_label = np.binary_repr(max_amplitude_idx, self._num_ancillae)[::-1] else: qc = self.construct_circuit(measurement=True) result = self._quantum_instance.execute(qc) ancilla_counts = result.get_counts(qc) top_measurement_label = \ sorted([(ancilla_counts[k], k) for k in ancilla_counts])[::-1][0][-1][::-1] top_measurement_decimal = sum([ t[0] * t[1] for t in zip(self._binary_fractions, [int(n) for n in top_measurement_label]) ]) self._ret['top_measurement_label'] = top_measurement_label self._ret['top_measurement_decimal'] = top_measurement_decimal self._ret['eigvals'] = \ [top_measurement_decimal / self._ret['stretch'] - self._ret['translation']] self._ret['energy'] = self._ret['eigvals'][0] def _run(self): self._compute_energy() return self._ret
class QPE(QuantumAlgorithm): """The Quantum Phase Estimation algorithm. QPE (also sometimes abbreviated as PEA, for Phase Estimation Algorithm), has two quantum registers, **control** and **target**, where the control consists of several qubits initially put in uniform superposition, and the target a set of qubits prepared in an eigenstate (often a guess of the eigenstate) of the unitary operator of a quantum system. QPE then evolves the target under the control using dynamics on the unitary operator. The information of the corresponding eigenvalue is then 'kicked-back' into the phases of the control register, which can then be deconvoluted by an Inverse Quantum Fourier Transform (IQFT), and measured for read-out in binary decimal format. QPE also requires a reasonably good estimate of the eigen wave function to start the process. For example, when estimating molecular ground energies in chemistry, the Hartree-Fock method could be used to provide such trial eigen wave functions. """ def __init__( self, operator: BaseOperator, state_in: Optional[InitialState], iqft: IQFT, num_time_slices: int = 1, num_ancillae: int = 1, expansion_mode: str = 'trotter', expansion_order: int = 1, shallow_circuit_concat: bool = False) -> None: """ Args: operator: The Hamiltonian Operator state_in: An optional InitialState component representing an initial quantum state. ``None`` may be supplied. iqft: A Inverse Quantum Fourier Transform component num_time_slices: The number of time slices, has a minimum value of 1. num_ancillae: The number of ancillary qubits to use for the measurement, has a min. value of 1. expansion_mode: The expansion mode ('trotter'|'suzuki') expansion_order: The suzuki expansion order, has a min. value of 1. shallow_circuit_concat: Set True to use shallow (cheap) mode for circuit concatenation of evolution slices. By default this is False. See :meth:`qiskit.aqua.operators.common.evolution_instruction` for more information. """ validate_min('num_time_slices', num_time_slices, 1) validate_min('num_ancillae', num_ancillae, 1) validate_in_set('expansion_mode', expansion_mode, {'trotter', 'suzuki'}) validate_min('expansion_order', expansion_order, 1) super().__init__() self._operator = op_converter.to_weighted_pauli_operator(operator.copy()) self._num_ancillae = num_ancillae self._ret = {} self._ret['translation'] = sum([abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([ [ self._ret['translation'], Pauli( np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits) ) ] ]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=state_in, iqft=iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat, pauli_list=self._pauli_list ) self._binary_fractions = [1 / 2 ** p for p in range(1, num_ancillae + 1)] def construct_circuit(self, measurement=False): """ Construct circuit. Args: measurement (bool): Boolean flag to indicate if measurement should be included in the circuit. Returns: QuantumCircuit: quantum circuit. """ qc = self._phase_estimation_circuit.construct_circuit(measurement=measurement) return qc def _compute_energy(self): if self._quantum_instance.is_statevector: qc = self.construct_circuit(measurement=False) result = self._quantum_instance.execute(qc) complete_state_vec = result.get_statevector(qc) ancilla_density_mat = get_subsystem_density_matrix( complete_state_vec, range(self._num_ancillae, self._num_ancillae + self._operator.num_qubits) ) ancilla_density_mat_diag = np.diag(ancilla_density_mat) max_amplitude = \ max(ancilla_density_mat_diag.min(), ancilla_density_mat_diag.max(), key=abs) max_amplitude_idx = np.where(ancilla_density_mat_diag == max_amplitude)[0][0] top_measurement_label = np.binary_repr(max_amplitude_idx, self._num_ancillae)[::-1] else: qc = self.construct_circuit(measurement=True) result = self._quantum_instance.execute(qc) ancilla_counts = result.get_counts(qc) top_measurement_label = \ sorted([(ancilla_counts[k], k) for k in ancilla_counts])[::-1][0][-1][::-1] top_measurement_decimal = sum( [t[0] * t[1] for t in zip(self._binary_fractions, [int(n) for n in top_measurement_label])] ) self._ret['top_measurement_label'] = top_measurement_label self._ret['top_measurement_decimal'] = top_measurement_decimal self._ret['eigvals'] = \ [top_measurement_decimal / self._ret['stretch'] - self._ret['translation']] self._ret['energy'] = self._ret['eigvals'][0] def _run(self): self._compute_energy() return self._ret
class QPE(QuantumAlgorithm, MinimumEigensolver): """The Quantum Phase Estimation algorithm. QPE (also sometimes abbreviated as PEA, for Phase Estimation Algorithm), has two quantum registers, **control** and **target**, where the control consists of several qubits initially put in uniform superposition, and the target a set of qubits prepared in an eigenstate (often a guess of the eigenstate) of the unitary operator of a quantum system. QPE then evolves the target under the control using dynamics on the unitary operator. The information of the corresponding eigenvalue is then 'kicked-back' into the phases of the control register, which can then be deconvoluted by an Inverse Quantum Fourier Transform (IQFT), and measured for read-out in binary decimal format. QPE also requires a reasonably good estimate of the eigen wave function to start the process. For example, when estimating molecular ground energies in chemistry, the Hartree-Fock method could be used to provide such trial eigen wave functions. """ def __init__( self, operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None, state_in: Optional[InitialState] = None, iqft: Optional[Union[QuantumCircuit, IQFT]] = None, num_time_slices: int = 1, num_ancillae: int = 1, expansion_mode: str = 'trotter', expansion_order: int = 1, shallow_circuit_concat: bool = False, quantum_instance: Optional[Union[QuantumInstance, BaseBackend]] = None ) -> None: """ Args: operator: The Hamiltonian Operator state_in: An optional InitialState component representing an initial quantum state. ``None`` may be supplied. iqft: A Inverse Quantum Fourier Transform component num_time_slices: The number of time slices, has a minimum value of 1. num_ancillae: The number of ancillary qubits to use for the measurement, has a min. value of 1. expansion_mode: The expansion mode ('trotter'|'suzuki') expansion_order: The suzuki expansion order, has a min. value of 1. shallow_circuit_concat: Set True to use shallow (cheap) mode for circuit concatenation of evolution slices. By default this is False. See :meth:`qiskit.aqua.operators.common.evolution_instruction` for more information. quantum_instance: Quantum Instance or Backend """ validate_min('num_time_slices', num_time_slices, 1) validate_min('num_ancillae', num_ancillae, 1) validate_in_set('expansion_mode', expansion_mode, {'trotter', 'suzuki'}) validate_min('expansion_order', expansion_order, 1) super().__init__(quantum_instance) self._state_in = state_in if isinstance(iqft, IQFT): warnings.warn( 'The qiskit.aqua.components.iqfts.IQFT module 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._shallow_circuit_concat = shallow_circuit_concat self._binary_fractions = [ 1 / 2**p for p in range(1, self._num_ancillae + 1) ] self._in_operator = operator self._operator = None self._ret = {} self._pauli_list = None self._phase_estimation_circuit = None self._setup(operator) def _setup( self, operator: Optional[Union[OperatorBase, LegacyBaseOperator]]) -> None: self._operator = None self._ret = {} self._pauli_list = None self._phase_estimation_circuit = None if operator: # Convert to Legacy Operator if Operator flow passed in if isinstance(operator, OperatorBase): operator = operator.to_legacy_op() self._operator = op_converter.to_weighted_pauli_operator( operator.copy()) self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=self._state_in, iqft=self._iqft, num_time_slices=self._num_time_slices, num_ancillae=self._num_ancillae, expansion_mode=self._expansion_mode, expansion_order=self._expansion_order, shallow_circuit_concat=self._shallow_circuit_concat, pauli_list=self._pauli_list) @property def operator(self) -> Optional[LegacyBaseOperator]: """ Returns operator """ return self._in_operator @operator.setter def operator(self, operator: Union[OperatorBase, LegacyBaseOperator]) -> None: """ set operator """ self._in_operator = operator self._setup(operator) @property def aux_operators( self) -> Optional[List[Union[OperatorBase, LegacyBaseOperator]]]: """ Returns aux operators """ raise TypeError('aux_operators not supported.') @aux_operators.setter def aux_operators( self, aux_operators: Optional[List[Union[OperatorBase, LegacyBaseOperator]]] ) -> None: """ Set aux operators """ raise TypeError('aux_operators not supported.') def construct_circuit(self, measurement: bool = False) -> QuantumCircuit: """ Construct circuit. Args: measurement: Boolean flag to indicate if measurement should be included in the circuit. Returns: QuantumCircuit: quantum circuit. """ if self._phase_estimation_circuit: return self._phase_estimation_circuit.construct_circuit( measurement=measurement) return None def compute_minimum_eigenvalue( self, operator: Optional[Union[OperatorBase, LegacyBaseOperator]] = None, aux_operators: Optional[List[Union[OperatorBase, LegacyBaseOperator]]] = None ) -> MinimumEigensolverResult: super().compute_minimum_eigenvalue(operator, aux_operators) return self._run() def _compute_energy(self): if self._quantum_instance.is_statevector: qc = self.construct_circuit(measurement=False) result = self._quantum_instance.execute(qc) complete_state_vec = result.get_statevector(qc) ancilla_density_mat = get_subsystem_density_matrix( complete_state_vec, range(self._num_ancillae, self._num_ancillae + self._operator.num_qubits)) ancilla_density_mat_diag = np.diag(ancilla_density_mat) max_amplitude = \ max(ancilla_density_mat_diag.min(), ancilla_density_mat_diag.max(), key=abs) max_amplitude_idx = np.where( ancilla_density_mat_diag == max_amplitude)[0][0] top_measurement_label = np.binary_repr(max_amplitude_idx, self._num_ancillae)[::-1] else: qc = self.construct_circuit(measurement=True) result = self._quantum_instance.execute(qc) ancilla_counts = result.get_counts(qc) top_measurement_label = \ sorted([(ancilla_counts[k], k) for k in ancilla_counts])[::-1][0][-1][::-1] top_measurement_decimal = sum([ t[0] * t[1] for t in zip(self._binary_fractions, [int(n) for n in top_measurement_label]) ]) self._ret['top_measurement_label'] = top_measurement_label self._ret['top_measurement_decimal'] = top_measurement_decimal self._ret['eigvals'] = \ [top_measurement_decimal / self._ret['stretch'] - self._ret['translation']] self._ret['energy'] = self._ret['eigvals'][0] def _run(self) -> 'QPEResult': self._compute_energy() result = QPEResult() if 'translation' in self._ret: result.translation = self._ret['translation'] if 'stretch' in self._ret: result.stretch = self._ret['stretch'] if 'top_measurement_label' in self._ret: result.top_measurement_label = self._ret['top_measurement_label'] if 'top_measurement_decimal' in self._ret: result.top_measurement_decimal = self._ret[ 'top_measurement_decimal'] if 'eigvals' in self._ret: result.eigenvalue = self._ret['eigvals'][0] return result
class QPE(QuantumAlgorithm): """The Quantum Phase Estimation algorithm.""" def __init__(self, operator: BaseOperator, state_in: InitialState, iqft: IQFT, num_time_slices: int = 1, num_ancillae: int = 1, expansion_mode: str = 'trotter', expansion_order: int = 1, shallow_circuit_concat: bool = False) -> None: """ Args: operator: the hamiltonian Operator object state_in: the InitialState component representing the initial quantum state iqft: the Inverse Quantum Fourier Transform component num_time_slices: the number of time slices, has a min. value of 1. num_ancillae: the number of ancillary qubits to use for the measurement, has a min. value of 1. expansion_mode: the expansion mode (trotter|suzuki) expansion_order: the suzuki expansion order, has a min. value of 1. shallow_circuit_concat: indicate whether to use shallow (cheap) mode for circuit concatenation """ validate_min('num_time_slices', num_time_slices, 1) validate_min('num_ancillae', num_ancillae, 1) validate_in_set('expansion_mode', expansion_mode, {'trotter', 'suzuki'}) validate_min('expansion_order', expansion_order, 1) super().__init__() self._operator = op_converter.to_weighted_pauli_operator( operator.copy()) self._num_ancillae = num_ancillae self._ret = {} self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=state_in, iqft=iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat, pauli_list=self._pauli_list) self._binary_fractions = [1 / 2**p for p in range(1, num_ancillae + 1)] def construct_circuit(self, measurement=False): """ Construct circuit. Args: measurement (bool): Boolean flag to indicate if measurement should be included in the circuit. Returns: QuantumCircuit: quantum circuit. """ qc = self._phase_estimation_circuit.construct_circuit( measurement=measurement) return qc def _compute_energy(self): if self._quantum_instance.is_statevector: qc = self.construct_circuit(measurement=False) result = self._quantum_instance.execute(qc) complete_state_vec = result.get_statevector(qc) ancilla_density_mat = get_subsystem_density_matrix( complete_state_vec, range(self._num_ancillae, self._num_ancillae + self._operator.num_qubits)) ancilla_density_mat_diag = np.diag(ancilla_density_mat) max_amplitude = \ max(ancilla_density_mat_diag.min(), ancilla_density_mat_diag.max(), key=abs) max_amplitude_idx = np.where( ancilla_density_mat_diag == max_amplitude)[0][0] top_measurement_label = np.binary_repr(max_amplitude_idx, self._num_ancillae)[::-1] else: qc = self.construct_circuit(measurement=True) result = self._quantum_instance.execute(qc) ancilla_counts = result.get_counts(qc) top_measurement_label = \ sorted([(ancilla_counts[k], k) for k in ancilla_counts])[::-1][0][-1][::-1] top_measurement_decimal = sum([ t[0] * t[1] for t in zip(self._binary_fractions, [int(n) for n in top_measurement_label]) ]) self._ret['top_measurement_label'] = top_measurement_label self._ret['top_measurement_decimal'] = top_measurement_decimal self._ret['eigvals'] = \ [top_measurement_decimal / self._ret['stretch'] - self._ret['translation']] self._ret['energy'] = self._ret['eigvals'][0] def _run(self): self._compute_energy() return self._ret
class QPE(QuantumAlgorithm): """The Quantum Phase Estimation algorithm.""" PROP_NUM_TIME_SLICES = 'num_time_slices' PROP_EXPANSION_MODE = 'expansion_mode' PROP_EXPANSION_ORDER = 'expansion_order' PROP_NUM_ANCILLAE = 'num_ancillae' _INPUT_SCHEMA = { '$schema': 'http://json-schema.org/draft-07/schema#', 'id': 'qpe_schema', 'type': 'object', 'properties': { PROP_NUM_TIME_SLICES: { 'type': 'integer', 'default': 1, 'minimum': 1 }, PROP_EXPANSION_MODE: { 'type': 'string', 'default': 'trotter', 'enum': ['suzuki', 'trotter'] }, PROP_EXPANSION_ORDER: { 'type': 'integer', 'default': 1, 'minimum': 1 }, PROP_NUM_ANCILLAE: { 'type': 'integer', 'default': 1, 'minimum': 1 } }, 'additionalProperties': False } def __init__(self, operator, state_in, iqft, num_time_slices=1, num_ancillae=1, expansion_mode='trotter', expansion_order=1, shallow_circuit_concat=False): """ Args: operator (BaseOperator): the hamiltonian Operator object state_in (InitialState): the InitialState component representing the initial quantum state iqft (IQFT): the Inverse Quantum Fourier Transform 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 shallow_circuit_concat (bool): indicate whether to use shallow (cheap) mode for circuit concatenation """ validate(locals(), self._INPUT_SCHEMA) super().__init__() self._operator = op_converter.to_weighted_pauli_operator( operator.copy()) self._num_ancillae = num_ancillae self._ret = {} self._ret['translation'] = sum( [abs(p[0]) for p in self._operator.reorder_paulis()]) self._ret['stretch'] = 0.5 / self._ret['translation'] # translate the operator self._operator.simplify() translation_op = WeightedPauliOperator([[ self._ret['translation'], Pauli(np.zeros(self._operator.num_qubits), np.zeros(self._operator.num_qubits)) ]]) translation_op.simplify() self._operator += translation_op self._pauli_list = self._operator.reorder_paulis() # stretch the operator for p in self._pauli_list: p[0] = p[0] * self._ret['stretch'] self._phase_estimation_circuit = PhaseEstimationCircuit( operator=self._operator, state_in=state_in, iqft=iqft, num_time_slices=num_time_slices, num_ancillae=num_ancillae, expansion_mode=expansion_mode, expansion_order=expansion_order, shallow_circuit_concat=shallow_circuit_concat, pauli_list=self._pauli_list) self._binary_fractions = [1 / 2**p for p in range(1, num_ancillae + 1)] def construct_circuit(self, measurement=False): """ Construct circuit. Args: measurement (bool): Boolean flag to indicate if measurement should be included in the circuit. Returns: QuantumCircuit: quantum circuit. """ qc = self._phase_estimation_circuit.construct_circuit( measurement=measurement) return qc def _compute_energy(self): if self._quantum_instance.is_statevector: qc = self.construct_circuit(measurement=False) result = self._quantum_instance.execute(qc) complete_state_vec = result.get_statevector(qc) ancilla_density_mat = get_subsystem_density_matrix( complete_state_vec, range(self._num_ancillae, self._num_ancillae + self._operator.num_qubits)) ancilla_density_mat_diag = np.diag(ancilla_density_mat) max_amplitude = \ max(ancilla_density_mat_diag.min(), ancilla_density_mat_diag.max(), key=abs) max_amplitude_idx = np.where( ancilla_density_mat_diag == max_amplitude)[0][0] top_measurement_label = np.binary_repr(max_amplitude_idx, self._num_ancillae)[::-1] else: qc = self.construct_circuit(measurement=True) result = self._quantum_instance.execute(qc) ancilla_counts = result.get_counts(qc) top_measurement_label = \ sorted([(ancilla_counts[k], k) for k in ancilla_counts])[::-1][0][-1][::-1] top_measurement_decimal = sum([ t[0] * t[1] for t in zip(self._binary_fractions, [int(n) for n in top_measurement_label]) ]) self._ret['top_measurement_label'] = top_measurement_label self._ret['top_measurement_decimal'] = top_measurement_decimal self._ret['eigvals'] = \ [top_measurement_decimal / self._ret['stretch'] - self._ret['translation']] self._ret['energy'] = self._ret['eigvals'][0] def _run(self): self._compute_energy() return self._ret