Source code for qiskit.aqua.components.uncertainty_problems.multivariate_problem

# -*- 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.

"""
Multivariate Uncertainty Problem.
"""

from typing import Optional, Union, List, Tuple
import numpy as np
from qiskit.aqua.utils import CircuitFactory
from qiskit.aqua.components.uncertainty_problems import UncertaintyProblem
from qiskit.aqua.components.uncertainty_models import MultivariateDistribution
from .univariate_piecewise_linear_objective import UnivariatePiecewiseLinearObjective


[docs]class MultivariateProblem(UncertaintyProblem): """ Multivariate Uncertainty Problem. """ def __init__(self, uncertainty_model: MultivariateDistribution, aggregation_function: CircuitFactory, univariate_objective: UnivariatePiecewiseLinearObjective, conditions: Optional[Union[List[Tuple[int, CircuitFactory]], np.ndarray]] = None) -> None: """ Constructor. Args: uncertainty_model: multivariate uncertainty model aggregation_function: aggregation function that maps the multiple dimension to an aggregated value univariate_objective: objective function applied to the aggregated value conditions: list of pairs (int, CircuitFactory) = target dimension of uncertainty model and condition to be satisfied to apply the aggregation """ # determine number of target qubits num_target_qubits = uncertainty_model.num_target_qubits + 1 super().__init__(num_target_qubits) # set qubit indices for self.i_state = list(range(num_target_qubits - 1)) self.i_objective = num_target_qubits - 1 # store parameters self._uncertainty_model = uncertainty_model self._aggregation_function = aggregation_function self._univariate_objective = univariate_objective self._conditions = conditions
[docs] def value_to_estimation(self, value): if hasattr(self._univariate_objective, 'value_to_estimation'): return self._univariate_objective.value_to_estimation(value) else: return value
[docs] def required_ancillas(self): num_condition_ancillas = 0 num_condition_target_ancillas = 0 num_aggregation_ancillas = self._aggregation_function.required_ancillas() if self._conditions is not None: num_condition_target_ancillas = len(self._conditions) + 1 * (len(self._conditions) > 1) num_aggregation_ancillas = self._aggregation_function.required_ancillas_controlled() if self._conditions is not None: for _, condition in self._conditions: num_condition_ancillas = np.maximum(num_condition_ancillas, condition.required_ancillas()) # get maximal number of required ancillas num_ancillas = max([self._uncertainty_model.required_ancillas(), num_aggregation_ancillas, self._univariate_objective.required_ancillas(), num_condition_ancillas]) # add ancillas that are required to compute intermediate # states are are no directly uncomputed num_ancillas += self._aggregation_function.num_sum_qubits num_ancillas += num_condition_target_ancillas return num_ancillas
[docs] def build(self, qc, q, q_ancillas=None, params=None): # apply uncertainty model (can use all ancillas and returns all clean) q_state = [q[i] for i in self.i_state] self._uncertainty_model.build(qc, q_state, q_ancillas) qc.barrier() # get all qubits up to the largest state qubit num_agg_qubits = self._aggregation_function.num_sum_qubits q_agg_in = q_state q_agg_out = [q_ancillas[i] for i in range(num_agg_qubits)] q_agg = q_agg_in + q_agg_out # determine objective qubits (aggregation qubits + objective qubit) q_obj = q_agg_out + [q[self.i_objective]] # set condition target qubits if self._conditions: i_cond_start = num_agg_qubits i_cond_end = i_cond_start + len(self._conditions) + 1 * (len(self._conditions) > 1) q_cond_target = [q_ancillas[i] for i in range(i_cond_start, i_cond_end)] # set remaining ancillas remaining_ancillas_start = i_cond_end else: # set remaining ancillas remaining_ancillas_start = num_agg_qubits q_rem_ancillas = [q_ancillas[i] for i in range(remaining_ancillas_start, len(q_ancillas))] # apply controlled or uncontrolled aggregation if not self._conditions: # apply aggregation self._aggregation_function.build(qc, q_agg, q_rem_ancillas) qc.barrier() # apply objective function self._univariate_objective.build(qc, q_obj, q_rem_ancillas) qc.barrier() # uncompute aggregation (all ancillas should be clean again now) self._aggregation_function.build_inverse(qc, q_agg, q_rem_ancillas) qc.barrier() else: if len(self._conditions) == 1: dimension = self._conditions[0][0] condition = self._conditions[0][1] i_condition_in_start = \ np.cumsum(self._uncertainty_model.num_qubits)[dimension] - \ self._uncertainty_model.num_qubits[dimension] i_condition_in_end = np.cumsum(self._uncertainty_model.num_qubits)[dimension] q_condition_in = \ [q_state[i] for i in range(i_condition_in_start, i_condition_in_end)] q_condition = q_condition_in + [q_cond_target[0]] condition.build(qc, q_condition, q_rem_ancillas) qc.barrier() # apply aggregation self._aggregation_function.build_controlled(qc, q_agg, q_cond_target[0], q_rem_ancillas, use_basis_gates=False) qc.barrier() # apply objective function self._univariate_objective.build(qc, q_obj, q_rem_ancillas) qc.barrier() # uncompute aggregation (all ancillas should be clean again now) self._aggregation_function.build_controlled_inverse(qc, q_agg, q_cond_target[0], q_rem_ancillas, use_basis_gates=False) qc.barrier() # uncompute condition condition.build_inverse(qc, q_condition, q_rem_ancillas) else: for j in range(len(self._conditions)): dimension = self._conditions[j][0] condition = self._conditions[j][1] i_condition_in_start = \ np.cumsum(self._uncertainty_model.num_qubits)[dimension] - \ self._uncertainty_model.num_qubits[dimension] i_condition_in_end = np.cumsum(self._uncertainty_model.num_qubits)[dimension] q_condition_in = \ [q_state[i] for i in range(i_condition_in_start, i_condition_in_end)] q_condition = q_condition_in + [q_cond_target[j]] condition.build(qc, q_condition, q_rem_ancillas) qc.mct(q_cond_target[:-1], q_cond_target[-1], q_rem_ancillas) qc.barrier() # apply aggregation self._aggregation_function.build_controlled(qc, q_agg, q_cond_target[-1], q_rem_ancillas, use_basis_gates=False) qc.barrier() # apply objective function self._univariate_objective.build(qc, q_obj, q_rem_ancillas) qc.barrier() # uncompute aggregation (all ancillas should be clean again now) self._aggregation_function.build_controlled_inverse(qc, q_agg, q_cond_target[-1], q_rem_ancillas, use_basis_gates=False) qc.barrier() qc.mct(q_cond_target[:-1], q_cond_target[-1], q_rem_ancillas) # uncompute condition for j in range(len(self._conditions)): dimension = self._conditions[j][0] condition = self._conditions[j][1] i_condition_in_start = \ np.cumsum(self._uncertainty_model.num_qubits)[dimension] - \ self._uncertainty_model.num_qubits[dimension] i_condition_in_end = np.cumsum(self._uncertainty_model.num_qubits)[dimension] q_condition_in = \ [q_state[i] for i in range(i_condition_in_start, i_condition_in_end)] q_condition = q_condition_in + [q_cond_target[j]] condition.build_inverse(qc, q_condition, q_rem_ancillas)