Source code for qiskit.aqua.circuits.weighted_sum_operator

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

# This code is part of Qiskit.
#
# (C) Copyright IBM 2019, 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.

"""Adds q^T * w to separate register for non-negative integer weights w."""

import logging

import numpy as np

from qiskit.circuit.library.arithmetic import WeightedAdder
from qiskit.aqua import AquaError
from qiskit.aqua.utils.circuit_factory import CircuitFactory

logger = logging.getLogger(__name__)


[docs]class WeightedSumOperator(CircuitFactory): """Adds q^T * w to separate register for non-negative integer weights w.""" def __init__(self, num_state_qubits, weights, i_state=None, i_sum=None): """Computes the weighted sum controlled by state qubits Args: num_state_qubits (int): number of state qubits weights (Union(list, numpy.ndarray)): weights per state qubits i_state (Optional(Union(list, numpy.ndarray))): indices of state qubits, set to range(num_state_qubits) if None i_sum (Optional(int)): indices of target qubits (that represent the resulting sum), set to range(num_state_qubits, num_state_qubits + req_num_sum_qubits) if None Raises: AquaError: invalid input """ self._weights = weights # check weights for i, w in enumerate(weights): if not np.isclose(w, np.round(w)): logger.warning('Non-integer weights are rounded to ' 'the nearest integer! (%s, %s).', i, w) self._num_state_qubits = num_state_qubits self._num_sum_qubits = self.get_required_sum_qubits(weights) self._num_carry_qubits = self.num_sum_qubits - 1 num_target_qubits = num_state_qubits + self.num_sum_qubits super().__init__(num_target_qubits) if i_state is None: self.i_state = list(range(num_state_qubits)) else: self.i_state = i_state if i_sum is None: self.i_sum = \ list(range(max(self.i_state) + 1, max(self.i_state) + self.num_sum_qubits + 1)) else: if len(i_sum) == self.get_required_sum_qubits(weights): self.i_sum = i_sum else: raise AquaError('Invalid number of sum qubits {}! Required {}'.format( len(i_sum), self.get_required_sum_qubits(weights) ))
[docs] @staticmethod def get_required_sum_qubits(weights): """ get required sum qubits """ return int(np.floor(np.log2(sum(weights))) + 1)
@property def weights(self): """ returns weights """ return self._weights @property def num_state_qubits(self): """ returns num state qubits """ return self._num_state_qubits @property def num_sum_qubits(self): """ returns num sum qubits """ return self._num_sum_qubits @property def num_carry_qubits(self): """ returns num carry qubits """ return self._num_carry_qubits
[docs] def required_ancillas(self): """ required ancillas """ if self.num_sum_qubits > 2: # includes one ancilla qubit for 3-controlled not gates # TODO: validate when the +1 is needed and make a case distinction return self.num_carry_qubits + 1 else: return self.num_carry_qubits
[docs] def required_ancillas_controlled(self): """ returns required ancillas controlled """ return self.required_ancillas()
[docs] def build(self, qc, q, q_ancillas=None, params=None): instr = WeightedAdder(num_state_qubits=self.num_state_qubits, weights=self.weights).to_instruction() qr = [q[i] for i in self.i_state + self.i_sum] if q_ancillas: qr += q_ancillas[:self.required_ancillas()] # pylint:disable=unnecessary-comprehension qc.append(instr, qr)