Преобразование Барроуза-Уиллера (BWT) повторяющаяся строка

Я пишу преобразование Барроуза-Уиллера и его обратное на Python. Он отлично работает для небольших струн, но развалился, когда я тестировал струны большего размера. Иногда кажется, что струна зацикливается. Я уверен, что это должно быть связано с последним циклом декодера, но я следую шагам, которые можно найти на нескольких веб-сайтах. Моя реализация выглядит следующим образом:

class BurrowsWheelerTransform:

    def __init__(self, data):
        self.data = data

    def transform(self):
        # get data size
        size = len(self.data)
        # get order (by index) of rotations
        order = sorted(range(size), key=lambda i: self.data[i:])
        # get index of original rotation
        index = order.index(0)
        # return size appended with last column of (imaginary) rotation table
        return chr(255) * (index // 255) + chr(index % 255) + ''.join(self.data[(i - 1 + size) % size] for i in order)

    def restore(self):
        # get index of end of index
        eoi = next(i for i in range(len(self.data)) if ord(self.data[i]) < 255)
        # get index
        index = 255 * eoi + ord(self.data[eoi])
        # get tranformed content
        content = self.data[eoi + 1:]
        # get lshift array
        lshift = [i - 1 for symbol in sorted(set(content)) for i, x in enumerate(self.data) if x == symbol]
        # restore
        restored = ''
        for i in range(len(content)):
            index = lshift[index]
            restored += content[index]
        # return restored
        return restored

Исходная строка:

Не желая навязываться на княжну, Роств не вернулся в дом, а остался в деревне в ожидании ее отъезда. Когда ее экипаж выехал из дома, он сел на нее и сопровождал ее в восьми милях от Богучрово до того места, где дорога была занята нашими войсками. В гостинице в Янкво он почтительно простился с ней, впервые позволив себе поцеловать ее руку.

Как ты можешь так говорить! он покраснел, отвечал принцессе Марис на выражения благодарности за ее избавление, как она назвала то, что произошло. Любой полицейский сделал бы столько же! "Если бы у нас были только крестьяне, мы бы не позволили врагу зайти так далеко", - сказал он с чувством стыда и, желая сменить тему. Я только рад возможности познакомиться с вами. До свидания, принцесса. Желаю вам счастья и утешения и надеюсь снова встретиться с вами в более счастливых обстоятельствах. Если ты не хочешь заставить меня покраснеть, пожалуйста, не благодари меня!

Расшифрованная строка:

Не желая навязываться на княжну, Роств не вернулся в дом, а остался в деревне в ожидании ее отъезда. Когда ее экипаж выехал из дома, он сел на нее и сопровождал ее в восьми милях от Богучрово до того места, где дорога была занята нашими войсками. В гостинице в Янкво он почтительно простился с ней, впервые позволив себе поцеловать ее руку.

Как можно так говорить! Не желая навязываться на княжну, Роств не вернулся в дом, а остался в деревне в ожидании ее отъезда. Когда ее экипаж выехал из дома, он сел на нее и сопровождал ее в восьми милях от Богучрово до того места, где дорога была занята нашими войсками. В гостинице в Янкво он почтительно простился с ней, впервые позволив себе поцеловать ее руку.

Как можно так говорить! Не желая навязываться на княжну, Роств не вернулся в дом, а остался в деревне в ожидании ее отъезда. когда

Как ни странно, похоже, что это происходит с другими реализациями, которые я нашел в Интернете и протестировал, например, этот и этот. Что здесь происходит? Я неправильно понял, как работает преобразование? Или это некорректная реализация?

1 ответ

Нашел ответ! Этот алгоритм основан на предположении, что строка объединена с одним конечным символом, который уникален и лексикографически меньше любого другого символа в строке. Однако, поскольку я намерен использовать любое значение в диапазоне 0-255 для любого данного символа, в моем распоряжении нет дополнительных символов. К счастью, благодаря Джону Курлаку и некоторым дополнительным исправлениям ошибок я смог немного изменить свою первоначальную реализацию, чтобы учесть этот факт. Вот:

class BurrowsWheelerTransform:

    def __init__(self, data):
        self.data = data

    def transform(self):
        # get data size
        size = len(self.data)
        # get doubled string
        self.data *= 2
        # get order (by index) of rotations
        order = sorted(range(size), key=lambda i: self.data[i:])
        # get index of original rotation
        index = order.index(0)
        # return index appended with last column of (imaginary) rotation table
        return chr(255) * (index // 255) + chr(index % 255) + ''.join(self.data[(i - 1 + size) % size] for i in order)

    def restore(self):
        # get index of end of index
        eoi = next(i for i in range(len(self.data)) if ord(self.data[i]) < 255)
        # get index
        index = 255 * eoi + ord(self.data[eoi])
        # get tranformed content
        content = self.data[eoi + 1:]
        size = len(content)
        # get lshift array
        lshift = [i for symbol in sorted(set(content)) for i, x in enumerate(content) if x == symbol]
        # restore
        restored = ''
        for i in range(size):
            index = lshift[index]
            if index >= size: break
            restored += content[index]
        # return restored
        return restored

Спасибо, Джон!

Я столкнулся с той же проблемой с алгоритмом сортировки BWT в C++, благодаря вашему комментарию я быстро исправил ее, используя 16-битный массив вместо 8-битного, чтобы разрешить значение выше 0xFF (255) для последнего символа (также пришлось изменить BWT код алгоритма сортировки немного, чтобы он принимал 16-битные данные). Теперь он отлично работает, спасибо.

Другие вопросы по тегам