# Path: preimage/utils/alphabet.py
# def get_n_gram_to_index(alphabet, n):
#     n_grams = get_n_grams(alphabet, n)
#     indexes = numpy.arange(len(n_grams))
#     n_gram_to_index = dict(zip(n_grams, indexes))
#     return n_gram_to_index
# 
# Path: preimage/exceptions/n_gram.py
# class InvalidNGramError(ValueError):
#     def __init__(self, n, n_gram):
#         self.n = n
#         self.n_gram = n_gram
# 
#     def __str__(self):
#         error_message = "{} is not a possible {:d}_gram for this alphabet".format(self.n_gram, self.n)
#         return error_message


from collections import Counter
from scipy.sparse import csr_matrix
from preimage.utils.alphabet import get_n_gram_to_index
from preimage.exceptions.n_gram import InvalidNGramError
import numpy
        samples and max_n_gram_count is the number of n-gram in the highest length string of Y.
    """
    n = int(n)
    n_examples = numpy.array(Y).shape[0]
    n_gram_to_index = get_n_gram_to_index(alphabet, n)
    index_pointers, indexes, data = __initialize_pointers_indexes_data(n_examples)
    __build_pointers_indexes_data_with_positions(index_pointers, indexes, data, n, n_gram_to_index, Y)
    n_columns = __get_n_columns(n, len(n_gram_to_index), Y)
    feature_space = __build_csr_matrix(index_pointers, indexes, data, n_examples, n_columns)
    return feature_space


def __get_n_columns(n, n_gram_count_in_alphabet, Y):
    y_max_n_gram_count = numpy.max([len(y) for y in Y]) - n + 1
    n_columns = y_max_n_gram_count * n_gram_count_in_alphabet
    return n_columns


def __build_pointers_indexes_data_with_positions(index_pointers, indexes, data, n, n_gram_to_index, Y):
    for y_index, y in enumerate(Y):
        y_n_gram_count = len(y) - n + 1
        index_pointers[y_index + 1] = index_pointers[y_index] + y_n_gram_count
        indexes += __get_y_column_indexes_with_positions(y, n, n_gram_to_index, y_n_gram_count)
        data += [1.] * y_n_gram_count


def __get_y_column_indexes_with_positions(y, n, n_gram_to_index, y_n_gram_count):
    try:
        column_indexes = [(i * len(n_gram_to_index)) + n_gram_to_index[y[i:i + n]] for i in range(y_n_gram_count)]
    except KeyError as key_error:

# Path: preimage/utils/alphabet.py
# def get_n_gram_to_index(alphabet, n):
#     n_grams = get_n_grams(alphabet, n)
#     indexes = numpy.arange(len(n_grams))
#     n_gram_to_index = dict(zip(n_grams, indexes))
#     return n_gram_to_index
# 
# Path: preimage/exceptions/n_gram.py
# class InvalidNGramError(ValueError):
#     def __init__(self, n, n_gram):
#         self.n = n
#         self.n_gram = n_gram
# 
#     def __str__(self):
#         error_message = "{} is not a possible {:d}_gram for this alphabet".format(self.n_gram, self.n)
#         return error_message


# Path: preimage/features/string_feature_space.py
from collections import Counter
from scipy.sparse import csr_matrix
from preimage.utils.alphabet import get_n_gram_to_index
from preimage.exceptions.n_gram import InvalidNGramError
import numpy

        samples and max_n_gram_count is the number of n-gram in the highest length string of Y.
    """
    n = int(n)
    n_examples = numpy.array(Y).shape[0]
    n_gram_to_index = get_n_gram_to_index(alphabet, n)
    index_pointers, indexes, data = __initialize_pointers_indexes_data(n_examples)
    __build_pointers_indexes_data_with_positions(index_pointers, indexes, data, n, n_gram_to_index, Y)
    n_columns = __get_n_columns(n, len(n_gram_to_index), Y)
    feature_space = __build_csr_matrix(index_pointers, indexes, data, n_examples, n_columns)
    return feature_space


def __get_n_columns(n, n_gram_count_in_alphabet, Y):
    y_max_n_gram_count = numpy.max([len(y) for y in Y]) - n + 1
    n_columns = y_max_n_gram_count * n_gram_count_in_alphabet
    return n_columns


def __build_pointers_indexes_data_with_positions(index_pointers, indexes, data, n, n_gram_to_index, Y):
    for y_index, y in enumerate(Y):
        y_n_gram_count = len(y) - n + 1
        index_pointers[y_index + 1] = index_pointers[y_index] + y_n_gram_count
        indexes += __get_y_column_indexes_with_positions(y, n, n_gram_to_index, y_n_gram_count)
        data += [1.] * y_n_gram_count


def __get_y_column_indexes_with_positions(y, n, n_gram_to_index, y_n_gram_count):
    try:
        column_indexes = [(i * len(n_gram_to_index)) + n_gram_to_index[y[i:i + n]] for i in range(y_n_gram_count)]
    except KeyError as key_error:

        raise InvalidNGramError(n, key_error.args[0])