# 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
            partition_weights = graph_weights
        else:
            partition_weights = graph_weights[i, :]
        return partition_weights

    def _get_max_string_end_indexes_in_range(self, graph, min_partition, n_partitions, is_normalized):
        norm = [n_gram_count for n_gram_count in range(min_partition + 1, n_partitions + 1)]
        norm = numpy.array(norm).reshape(-1, 1)
        if is_normalized:
            graph[min_partition:, :] *= 1. / numpy.sqrt(norm)
            end_indexes = numpy.unravel_index(numpy.argmax(graph[min_partition:, :]), graph[min_partition:, :].shape)
        else:
            graph[min_partition:, :] = norm - 2 * graph[min_partition:, :]
            end_indexes = numpy.unravel_index(numpy.argmin(graph[min_partition:, :]), graph[min_partition:, :].shape)
        partition_index = end_indexes[0] + min_partition - 1
        return partition_index, end_indexes[1]

    def _build_max_string(self, partition_index, n_gram_index, predecessors):
        max_string = self._index_to_n_gram[n_gram_index]
        best_index = n_gram_index
        for i in range(partition_index, -1, -1):
            best_index = predecessors[i, best_index]
            max_string = self._index_to_n_gram[best_index][0] + max_string
        return max_string

    def _verify_graph_weights_and_y_length(self, graph_weights, n_partitions):
        if n_partitions <= 0:
            raise InvalidYLengthError(self.n, n_partitions + self.n - 1)
        valid_shapes = [(self._n_gram_count,), (n_partitions, self._n_gram_count)]
        if graph_weights.shape not in valid_shapes:

# 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

            partition_weights = graph_weights
        else:
            partition_weights = graph_weights[i, :]
        return partition_weights

    def _get_max_string_end_indexes_in_range(self, graph, min_partition, n_partitions, is_normalized):
        norm = [n_gram_count for n_gram_count in range(min_partition + 1, n_partitions + 1)]
        norm = numpy.array(norm).reshape(-1, 1)
        if is_normalized:
            graph[min_partition:, :] *= 1. / numpy.sqrt(norm)
            end_indexes = numpy.unravel_index(numpy.argmax(graph[min_partition:, :]), graph[min_partition:, :].shape)
        else:
            graph[min_partition:, :] = norm - 2 * graph[min_partition:, :]
            end_indexes = numpy.unravel_index(numpy.argmin(graph[min_partition:, :]), graph[min_partition:, :].shape)
        partition_index = end_indexes[0] + min_partition - 1
        return partition_index, end_indexes[1]

    def _build_max_string(self, partition_index, n_gram_index, predecessors):
        max_string = self._index_to_n_gram[n_gram_index]
        best_index = n_gram_index
        for i in range(partition_index, -1, -1):
            best_index = predecessors[i, best_index]
            max_string = self._index_to_n_gram[best_index][0] + max_string
        return max_string

    def _verify_graph_weights_and_y_length(self, graph_weights, n_partitions):
        if n_partitions <= 0:
            raise InvalidYLengthError(self.n, n_partitions + self.n - 1)
        valid_shapes = [(self._n_gram_count,), (n_partitions, self._n_gram_count)]
        if graph_weights.shape not in valid_shapes:

            raise InvalidShapeError('graph_weights', graph_weights.shape, valid_shapes)