"""QIF channels."""
from qiflib.core.secrets import Secrets
from qiflib.util.probability import check_prob_distribution
from qiflib.util.types import is_list, is_2d_list_matrix, is_2d_numpy_matrix
from numpy import arange, array
[docs]
class Channel:
"""Class used to represent a channel. To create an instance of this
class it is necessary to have an instance of :py:class:`.Secrets` class
and a channel matrix C :math:`n{\\times}m` where :math:`n` is the number
of secrets, :math:`m` is the number of outputs in the channel and
:code:`C[x][y]` is the conditional probability :math:`p(y|x)` of the
channel outputs :math:`y` when the value of the secret is :math:`x`.
Parameters
----------
secrets : core.Secrets
Secrets object.
outputs : list
Outputs labels.
channel : numpy.ndarray
Channel matrix. Each line must be a probability distribution.
Attributes
----------
secrets : core.Secrets
Set of secrets.
outputs : list
List of channel outputs labels.
num_ouputs : int
Number of outputs in the channel.
matrix : list, numpy.ndarray
Channel matrix where :code:`C[x][y]` is the conditional probability
:math:`p(y|x)` of the channel outputs :math:`y` when the value of
the secret is :math:`x`.
"""
def __init__(self, secrets, outputs, channel):
self._check_types(secrets, outputs, channel)
self._check_sizes(secrets, outputs, channel)
self._check_channel_matrix(channel)
self.secrets = secrets
self.outputs = outputs
self.matrix = array(channel)
self.num_outputs = len(outputs)
[docs]
def update_prior(self, prior):
"""Update the prior distribution on set of secrets.
The number of secrets must match the current number of rows of the channel.
Parameters
----------
prior : list, numpy.ndarray
Prior distribution on the set of secrets. prior[i] is the
probability of secret named labels[i] beeing the real secret.
"""
self.secrets.update_prior(prior)
def _check_types(self, secrets, outputs, channel):
if type(secrets) != type(Secrets(['x1','x2'], [1,0])):
raise TypeError('The parameter \'secrets\' must be a core.secrets.Secrets object')
if not is_list(outputs):
raise TypeError('The parameter \'outputs\' must be a list')
if not is_2d_list_matrix(channel) and not is_2d_numpy_matrix(channel):
raise TypeError('The parameter \'channel\' must be a 2d matrix ' +
'(list of lists or a numpy.ndarray with 2 dimensions)')
def _check_sizes(self, secrets, outputs, channel):
if secrets.num_secrets != len(channel):
raise Exception('The number of rows in channel matrix must be the ' +
'same as the number of secrets')
if len(outputs) != len(channel[0]):
raise Exception('The number of columns in channel matrix must be ' +
'the same as the number of outputs (second parameter)')
if len(outputs) < 1:
raise Exception('The channel must have at least one output')
for i in arange(secrets.num_secrets):
if len(channel[i]) < 0:
raise Exception('There is an empty row in the channel matrix')
def _check_channel_matrix(self, channel):
# Check if each line of the channel matrix is a probability distribution
for i in arange(len(channel)):
check_prob_distribution(channel[i])