Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Fix to MultivariateDistribution class, Add Data Discretization & Truncation function #741

Merged
merged 21 commits into from
Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e534fed
bug fix multivariate variational distribution
Zoufalc Aug 14, 2019
a2c0d97
Update qgan.py
Zoufalc Aug 14, 2019
2aacfd6
Merge remote-tracking branch 'upstream/master' into master_ouf
Zoufalc Aug 15, 2019
dc07dd7
Merge remote-tracking branch 'upstream/master' into master_ouf
Zoufalc Aug 22, 2019
8b65cfd
Remove jsonschema cap
mtreinish Aug 23, 2019
d5a03eb
Merge pull request #668 from mtreinish/uncap-jsonschema-stable
manoelmarques Aug 26, 2019
a485208
Merge remote-tracking branch 'upstream/master' into master_ouf
Zoufalc Oct 4, 2019
db29da1
Merge remote-tracking branch 'upstream/stable' into master_ouf
Zoufalc Oct 11, 2019
f702121
Merge remote-tracking branch 'upstream/master' into master_ouf
Zoufalc Oct 11, 2019
9c77fe6
Merge remote-tracking branch 'upstream/master' into master_ouf
Zoufalc Nov 11, 2019
2033696
Merge remote-tracking branch 'upstream/master' into master_ouf
Zoufalc Dec 5, 2019
a60a152
fix constructor Multivaritate Distributions
Zoufalc Dec 5, 2019
9186dbc
fix lint
Zoufalc Dec 5, 2019
a2dc215
Update CHANGELOG.md
Zoufalc Dec 5, 2019
e4076ff
outsource data preparation from qgans into utils/dataset_helper.py
Zoufalc Dec 6, 2019
7d4272c
Update qgan.py
Zoufalc Dec 6, 2019
875fd9f
fix discretization&truncation lint
Zoufalc Dec 6, 2019
691bf9a
Merge branch 'master' into master_ouf
woodsp-ibm Dec 6, 2019
35100db
Update aqgd.py
Zoufalc Dec 6, 2019
4305f6d
Merge branch 'master_ouf' of https://github.com/Zoufalc/qiskit-aqua i…
Zoufalc Dec 6, 2019
fce19de
Update aqgd.py
woodsp-ibm Dec 6, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Added
Fixed
-------

- fix parameter ordering in the init of the multivariate distribution class (#741)
- fix bug in list concatenation in VQC algorithm (#733)
- A bug where `UCCSD` might generate an empty operator and try to evolve it. (#680)
- Decompose causes DAG failure using feature maps. (#719)
Expand Down
78 changes: 6 additions & 72 deletions qiskit/aqua/algorithms/adaptive/qgan/qgan.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
Quantum Generative Adversarial Network.
"""

from copy import deepcopy
import csv
import os
import logging
Expand All @@ -29,6 +28,7 @@
from qiskit.aqua.algorithms import QuantumAlgorithm
from qiskit.aqua.components.neural_networks.quantum_generator import QuantumGenerator
from qiskit.aqua.components.neural_networks.numpy_discriminator import NumpyDiscriminator
from qiskit.aqua.utils.dataset_helper import discretize_and_truncate

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -145,15 +145,13 @@ def __init__(self, data, bounds=None, num_qubits=None, batch_size=500, num_epoch
if np.ndim(data) > 1:
if self._num_qubits is None:
self._num_qubits = np.ones[len(data[0])]*3
self._prob_data = \
np.zeros(int(np.prod(np.power(np.ones(len(self._data[0]))*2, self._num_qubits))))
else:
if self._num_qubits is None:
self._num_qubits = np.array([3])
self._prob_data = np.zeros(int(np.prod(np.power(np.array([2]), self._num_qubits))))
self._data_grid = []
self._grid_elements = None
self._prepare_data()
self._data, self._data_grid, self._grid_elements, self._prob_data = \
discretize_and_truncate(self._data, self._bounds, self._num_qubits,
return_data_grid_elements=True,
return_prob=True, prob_non_zero=True)
self._batch_size = batch_size
self._num_epochs = num_epochs
self._snapshot_dir = snapshot_dir
Expand Down Expand Up @@ -302,77 +300,13 @@ def rel_entr(self):
""" returns relative entropy """
return self._rel_entr

def _prepare_data(self):
"""
Discretize and truncate the input data such that it
is compatible wih the chosen data resolution.
"""
# Truncate the data
if np.ndim(self._bounds) == 1:
bounds = np.reshape(self._bounds, (1, len(self._bounds)))
else:
bounds = self._bounds
self._data = self._data.reshape((len(self._data), len(self._num_qubits)))
temp = []
for i, data_sample in enumerate(self._data):
append = True
for j, entry in enumerate(data_sample):
if entry < bounds[j, 0]:
append = False
if entry > bounds[j, 1]:
append = False
if append:
temp.append(list(data_sample))
self._data = np.array(temp)

# Fit the data to the data resolution. i.e. grid
for j, prec in enumerate(self._num_qubits):
data_row = self._data[:, j] # dim j of all data samples
# prepare data grid for dim j
grid = np.linspace(bounds[j, 0], bounds[j, 1], (2 ** prec))
# find index for data sample in grid
index_grid = np.searchsorted(grid, data_row-(grid[1]-grid[0])*0.5)
for k, index in enumerate(index_grid):
self._data[k, j] = grid[index]
if j == 0:
if len(self._num_qubits) > 1:
self._data_grid = [grid]
else:
self._data_grid = grid
self._grid_elements = grid
elif j == 1:
self._data_grid.append(grid)
temp = []
for g_e in self._grid_elements:
for g in grid:
temp0 = [g_e]
temp0.append(g)
temp.append(temp0)
self._grid_elements = temp
else:
self._data_grid.append(grid)
temp = []
for g_e in self._grid_elements:
for g in grid:
temp0 = deepcopy(g_e)
temp0.append(g)
temp.append(temp0)
self._grid_elements = deepcopy(temp)
self._data_grid = np.array(self._data_grid)
self._data = np.reshape(self._data, (len(self._data), len(self._data[0])))
for data in self._data:
for i, element in enumerate(self._grid_elements):
if all(data == element):
self._prob_data[i] += 1 / len(self._data)
self._prob_data = [1e-10 if x == 0 else x for x in self._prob_data]

def get_rel_entr(self):
""" get relative entropy """
samples_gen, prob_gen = self._generator.get_output(self._quantum_instance)
temp = np.zeros(len(self._grid_elements))
for j, sample in enumerate(samples_gen):
for i, element in enumerate(self._grid_elements):
if all(sample == element):
if sample == element:
temp[i] += prob_gen[j]
prob_gen = temp
prob_gen = [1e-8 if x == 0 else x for x in prob_gen]
Expand Down
1 change: 0 additions & 1 deletion qiskit/aqua/components/optimizers/aqgd.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ def deriv(self, j, params, obj):
params (array): Current value of the parameters to evaluate
the objective function at.
obj (callable): Objective function.

Returns:
float: The derivative of the objective function w.r.t. j
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class MultivariateDistribution(UncertaintyModel, ABC):
def get_section_key_name(cls):
return Pluggable.SECTION_KEY_MULTIVARIATE_DIST

def __init__(self, num_qubits, low, high, probabilities=None):
def __init__(self, num_qubits, probabilities=None, low=None, high=None):
"""
Constructor.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def __init__(self, num_qubits, low=None, high=None, mu=None, cov=None):
self.cov = cov
probs, values = self._compute_probabilities([], [], num_qubits, low, high)
probs = np.asarray(probs) / np.sum(probs)
super().__init__(num_qubits, low, high, probs)
super().__init__(num_qubits, probs, low, high)
self._values = values

def _compute_probabilities(self, probs, values, num_qubits, low, high, x=None):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def __init__(self, num_qubits, low=None, high=None, mu=None, sigma=None):
self.sigma = sigma
probs = self._compute_probabilities([], num_qubits, low, high)
probs = np.asarray(probs) / np.sum(probs)
super().__init__(num_qubits, low, high, probs)
super().__init__(num_qubits, probs, low, high)

def _compute_probabilities(self, probs, num_qubits, low, high, x=None):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def __init__(self, num_qubits, low=None, high=None):

num_values = np.prod([2**n for n in num_qubits])
probabilities = np.ones(num_values)
super().__init__(num_qubits, low, high, probabilities)
super().__init__(num_qubits, probabilities, low, high)

def build(self, qc, q, q_ancillas=None, params=None):
if params is None or params['i_state'] is None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class UnivariateDistribution(UncertaintyModel, ABC):
def get_section_key_name(cls):
return Pluggable.SECTION_KEY_UNIVARIATE_DIST

def __init__(self, num_target_qubits, probabilities, low=0, high=1):
def __init__(self, num_target_qubits, probabilities=None, low=0, high=1):
"""
Abstract univariate distribution class
Args:
Expand All @@ -53,8 +53,9 @@ def __init__(self, num_target_qubits, probabilities, low=0, high=1):
self._low = low
self._high = high
self._values = np.linspace(low, high, self.num_values)
if self.num_values != len(probabilities):
raise AquaError('num qubits and length of probabilities vector do not match!')
if probabilities is not None:
if self.num_values != len(probabilities):
raise AquaError('num qubits and length of probabilities vector do not match!')

@property
def low(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,12 @@ def __init__(self, num_qubits, var_form, params, low=0, high=1):
self._num_qubits = num_qubits
self._var_form = var_form
self.params = params
probabilities = list(np.zeros(2**num_qubits))
if isinstance(num_qubits, int):
probabilities = np.zeros(2 ** num_qubits)
elif isinstance(num_qubits, float):
probabilities = np.zeros(2 ** int(num_qubits))
else:
probabilities = np.zeros(2 ** sum(num_qubits))
super().__init__(num_qubits, probabilities, low, high)

@classmethod
Expand Down
106 changes: 105 additions & 1 deletion qiskit/aqua/utils/dataset_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
""" Data set helper """

import operator

from copy import deepcopy
import numpy as np
from sklearn.decomposition import PCA

Expand Down Expand Up @@ -133,3 +133,107 @@ def reduce_dim_to_via_pca(x, dim):
"""
x_reduced = PCA(n_components=dim).fit_transform(x)
return x_reduced


def discretize_and_truncate(data, bounds, num_qubits, return_data_grid_elements=False,
return_prob=False, prob_non_zero=True):
"""
Discretize & truncate classical data to enable digital encoding in qubit registers
whereby the data grid is [[grid elements dim 0],..., [grid elements dim k]]

Args:
data (list or array or np.array): training data (int or float) of dimension k
bounds (list or array or np.array): k min/max data values
[[min_0,max_0],...,[min_k-1,max_k-1]] if univariate data: [min_0,max_0]
num_qubits (list or array or np.array): k numbers of qubits to determine
representation resolution, i.e. n qubits enable the representation of 2**n
values [num_qubits_0,..., num_qubits_k-1]
return_data_grid_elements (Bool): if True - return an array with the data grid
elements
return_prob (Bool): if True - return a normalized frequency count of the discretized and
truncated data samples
prob_non_zero (Bool): if True - set 0 values in the prob_data to 10^-1 to avoid potential
problems when using the probabilities in loss functions - division by 0

Returns:
array: discretized and truncated data
array: data grid [[grid elements dim 0],..., [grid elements dim k]]
array: grid elements, Product_j=0^k-1 2**num_qubits_j element vectors
array: data probability, normalized frequency count sorted from smallest to biggest element

"""
# Truncate the data
if np.ndim(bounds) == 1:
bounds = np.reshape(bounds, (1, len(bounds)))

data = data.reshape((len(data), len(num_qubits)))
temp = []
for i, data_sample in enumerate(data):
append = True
for j, entry in enumerate(data_sample):
if entry < bounds[j, 0]:
append = False
if entry > bounds[j, 1]:
append = False
if append:
temp.append(list(data_sample))
data = np.array(temp)

# Fit the data to the data element grid
for j, prec in enumerate(num_qubits):
data_row = data[:, j] # dim j of all data samples
# prepare element grid for dim j
elements_current_dim = np.linspace(bounds[j, 0], bounds[j, 1], (2 ** prec))
# find index for data sample in grid
index_grid = np.searchsorted(elements_current_dim,
data_row-(elements_current_dim[1]-elements_current_dim[0])*0.5)
for k, index in enumerate(index_grid):
data[k, j] = elements_current_dim[index]
if j == 0:
if len(num_qubits) > 1:
data_grid = [elements_current_dim]
else:
data_grid = elements_current_dim
grid_elements = elements_current_dim
elif j == 1:
temp = []
for grid_element in grid_elements:
for element_current in elements_current_dim:
temp.append([grid_element, element_current])
grid_elements = temp
data_grid.append(elements_current_dim)
else:
temp = []
for grid_element in grid_elements:
for element_current in elements_current_dim:
temp.append(deepcopy(grid_element).append(element_current))
grid_elements = deepcopy(temp)
data_grid.append(elements_current_dim)
data_grid = np.array(data_grid)

data = np.reshape(data, (len(data), len(data[0])))

if return_prob:
if np.ndim(data) > 1:
prob_data = np.zeros(int(np.prod(np.power(np.ones(len(data[0])) * 2, num_qubits))))
else:
prob_data = np.zeros(int(np.prod(np.power(np.array([2]), num_qubits))))
for data_element in data:
for i, element in enumerate(grid_elements):
if all(data_element == element):
prob_data[i] += 1 / len(data)
if prob_non_zero:
# add epsilon to avoid 0 entries which can be problematic in loss functions (division)
prob_data = [1e-10 if x == 0 else x for x in prob_data]

if return_data_grid_elements:
return data, data_grid, grid_elements, prob_data
else:
return data, data_grid, prob_data

else:
if return_data_grid_elements:
return data, data_grid, grid_elements

else:
return data, data_grid