# -*- 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.
"""
This module contains the definition of a base class for multivariate distributions.
"""
from typing import Optional, List, Union, Dict
from abc import ABC
import numpy as np
from qiskit.aqua.components.initial_states import Custom
from .uncertainty_model import UncertaintyModel
[docs]class MultivariateDistribution(UncertaintyModel, ABC):
"""
This module contains the definition of a base class for multivariate distributions.
(Interface for discrete bounded uncertainty models assuming an equidistant grid)
"""
def __init__(self,
num_qubits: Union[List[int], np.ndarray],
probabilities: Optional[Dict] = None,
low: Optional[Union[List[float], np.ndarray]] = None,
high: Optional[Union[List[float], np.ndarray]] = None) -> None:
"""
Args:
num_qubits: Assigns qubits to dimensions
probabilities: Map - maps index tuples to probabilities
low: Lowest value per dimension
high: Highest value per dimension
"""
self._values = 0
# derive dimension from qubit assignment
self._dimension = len(num_qubits)
self._num_qubits = num_qubits
# derive total number of required qubits
num_target_qubits = 0
for i in range(self._dimension):
num_target_qubits += num_qubits[i]
# call super constructor
super().__init__(num_target_qubits)
self._num_values = []
for i in range(self._dimension):
self._num_values += [2 ** num_qubits[i]]
if probabilities is not None:
# normalize probabilities
probabilities = np.asarray(probabilities)
probabilities = probabilities / np.sum(probabilities)
self._probabilities = probabilities
self._probabilities_vector = np.reshape(probabilities, 2**num_target_qubits)
self._probabilities_vector = np.asarray(self._probabilities_vector)
else:
self._probabilities = None
self._probabilities_vector = None
if low is not None:
self._low = low
else:
self._low = np.zeros(self.dimension)
if high is not None:
self._high = high
else:
self._high = np.zeros(self.dimension)
for i in range(self.dimension):
self._high[i] = 2**num_qubits[i] - 1
@property
def num_qubits(self):
""" returns num qubits """
return self._num_qubits
@property
def dimension(self):
""" returns dimensions """
return self._dimension
@property
def low(self):
""" returns low """
return self._low
@property
def high(self):
""" returns high """
return self._high
@property
def num_values(self):
""" returns number of values """
return self._num_values
@property
def values(self):
""" returns values """
return self._values
@property
def probabilities(self):
""" returns probabilities """
return self._probabilities
@property
def probabilities_vector(self):
""" returns probabilities vector """
return self._probabilities_vector
[docs] def build(self, qc, q, q_ancillas=None, params=None):
""" build """
custom_state = Custom(self.num_target_qubits,
state_vector=np.sqrt(self._probabilities_vector))
qc.extend(custom_state.construct_circuit('circuit', q))
[docs] @staticmethod
def pdf_to_probabilities(pdf, low, high, num_values):
""" pdf to probabilities """
probabilities = np.zeros(num_values)
values = np.linspace(low, high, num_values)
total = 0
for i, _ in enumerate(values):
probabilities[i] = pdf(values[i])
total += probabilities[i]
probabilities /= total
return probabilities, values