# Path: preimage/utils/alphabet.py
# def get_index_to_n_gram(alphabet, n):
#     n_grams = get_n_grams(alphabet, n)
#     indexes = numpy.arange(len(n_grams))
#     index_to_n_gram = dict(zip(indexes, n_grams))
#     return index_to_n_gram
# 
# Path: preimage/exceptions/shape.py
# class InvalidShapeError(ValueError):
#     def __init__(self, parameter_name, parameter_shape, valid_shapes):
#         self.parameter_name = parameter_name
#         self.parameter_shape = parameter_shape
#         self.valid_shapes = [str(valid_shape) for valid_shape in valid_shapes]
# 
#     def __str__(self):
#         valid_shapes_string = ' or '.join(self.valid_shapes)
#         error_message = "{} wrong shape: Expected: {} Got: {}".format(self.parameter_name, valid_shapes_string,
#                                                                       str(self.parameter_shape))
#         return error_message
# 
# Path: preimage/exceptions/n_gram.py
# class InvalidYLengthError(ValueError):
#     def __init__(self, n, y_length):
#         self.n = n
#         self.y_length = y_length
# 
#     def __str__(self):
#         error_message = 'y_length must be >= n. Got: y_length={:d}, n={:d}'.format(self.y_length, self.n)
#         return error_message
# 
# class InvalidMinLengthError(ValueError):
#     def __init__(self, min_length, max_length):
#         self.min_length = min_length
#         self.max_length = max_length
# 
#     def __str__(self):
#         error_message = 'min_length must be <= max_length. ' \
#                         'Got: min_length={:d}, max_length={:d}'.format(self.min_length, self.max_length)
#         return error_message


import numpy
from preimage.utils.alphabet import get_index_to_n_gram
from preimage.exceptions.shape import InvalidShapeError
from preimage.exceptions.n_gram import InvalidYLengthError, InvalidMinLengthError
__author__ = 'amelie'




class GraphBuilder:
    """Graph builder for the pre-image of multiple string kernels.

    Solves the pre-image problem of string kernels with constant norms (Hamming, Weighted Degree). For string kernel
    where the norm is not constant, it builds a graph that can be used to compute the bounds of partial solutions in
    a branch and bound search. The graph is constructed by dynamic programming.

    Attributes
    ----------
    alphabet : list
        List of letters.
    n : int
        N-gram length.
    """
    def __init__(self, alphabet, n):
        self.alphabet = alphabet
        self.n = int(n)
        self._n_gram_count = len(self.alphabet) ** self.n
        self._entering_edges = self._get_entering_edge_indexes(self._n_gram_count, alphabet, n)

# Path: preimage/utils/alphabet.py
# def get_index_to_n_gram(alphabet, n):
#     n_grams = get_n_grams(alphabet, n)
#     indexes = numpy.arange(len(n_grams))
#     index_to_n_gram = dict(zip(indexes, n_grams))
#     return index_to_n_gram
# 
# Path: preimage/exceptions/shape.py
# class InvalidShapeError(ValueError):
#     def __init__(self, parameter_name, parameter_shape, valid_shapes):
#         self.parameter_name = parameter_name
#         self.parameter_shape = parameter_shape
#         self.valid_shapes = [str(valid_shape) for valid_shape in valid_shapes]
# 
#     def __str__(self):
#         valid_shapes_string = ' or '.join(self.valid_shapes)
#         error_message = "{} wrong shape: Expected: {} Got: {}".format(self.parameter_name, valid_shapes_string,
#                                                                       str(self.parameter_shape))
#         return error_message
# 
# Path: preimage/exceptions/n_gram.py
# class InvalidYLengthError(ValueError):
#     def __init__(self, n, y_length):
#         self.n = n
#         self.y_length = y_length
# 
#     def __str__(self):
#         error_message = 'y_length must be >= n. Got: y_length={:d}, n={:d}'.format(self.y_length, self.n)
#         return error_message
# 
# class InvalidMinLengthError(ValueError):
#     def __init__(self, min_length, max_length):
#         self.min_length = min_length
#         self.max_length = max_length
# 
#     def __str__(self):
#         error_message = 'min_length must be <= max_length. ' \
#                         'Got: min_length={:d}, max_length={:d}'.format(self.min_length, self.max_length)
#         return error_message


# Path: preimage/inference/graph_builder.py
import numpy
from preimage.utils.alphabet import get_index_to_n_gram
from preimage.exceptions.shape import InvalidShapeError
from preimage.exceptions.n_gram import InvalidYLengthError, InvalidMinLengthError

__author__ = 'amelie'




class GraphBuilder:
    """Graph builder for the pre-image of multiple string kernels.

    Solves the pre-image problem of string kernels with constant norms (Hamming, Weighted Degree). For string kernel
    where the norm is not constant, it builds a graph that can be used to compute the bounds of partial solutions in
    a branch and bound search. The graph is constructed by dynamic programming.

    Attributes
    ----------
    alphabet : list
        List of letters.
    n : int
        N-gram length.
    """
    def __init__(self, alphabet, n):
        self.alphabet = alphabet
        self.n = int(n)
        self._n_gram_count = len(self.alphabet) ** self.n
        self._entering_edges = self._get_entering_edge_indexes(self._n_gram_count, alphabet, n)

        self._index_to_n_gram = get_index_to_n_gram(alphabet, self.n)