вычисление сложности Лемпеля-Зива (LZ) (также известной как сложность последовательности) двоичной строки

Мне нужно вычислить LZ-сложность двоичной строки. LZ-сложность — это количество разностных подстрок, встречающихся при просмотре потока от начала до конца. Например:

s = 1001111011000010

Разметка в разных подстроках сложности последовательности c(s) = 6: s = 1 / 0 / 01 / 1110 / 1100 / 0010 /

может ли кто-нибудь помочь мне найти простое решение для этого? Я уверен, что должны быть какие-то очень простые реализации для этой известной проблемы, но мне трудно их найти. Можно ли это сделать просто с помощью построения дерева суффиксов или чего-то подобного. Если да, то как именно? а что мне делать?

кто-нибудь знает какой-либо исходный код c/c++ для выполнения задачи?

заранее спасибо.

уточнить предложенную в ответах конструкцию дерева. Дерево выглядит так?

         o
       /   \
      o     o
     / \   / \
    o   o o   o
       /     /
      o     o

person Arash    schedule 09.02.2011    source источник


Ответы (7)


Ниже приведен краткий пример того, как вычислить LZ-сложность с помощью дерева. Для удобства - мой; не ваш - этот код реализует предварительно выделенное дерево фиксированного размера и является ярким примером того, почему указатели void* уродливы в использовании и сложны в обслуживании. Дайте этот код как есть, и ваш лектор, скорее всего, выстрелит вам в лицо :)

#include <stdlib.h>
#include <stdio.h>

int LZComplexity(char *p_binarySequence, int p_maxTreeNodes)
{
 void **patternTree;
 void **currentNode;
 void **nextFreeNode;
 int nodeCount;
 int sequenceIndex;
 int currentDigit;

 nodeCount = 0;
 patternTree = malloc(sizeof(void*) * (p_maxTreeNodes << 1));
 currentNode = patternTree;
 nextFreeNode = patternTree + (sizeof(void*) << 1);
 currentNode[0] = NULL;
 currentNode[1] = NULL;
 sequenceIndex = 0;

 while (p_binarySequence[sequenceIndex])
 {
  currentDigit = p_binarySequence[sequenceIndex] - 48;
  if (NULL == currentNode[currentDigit])
  {
   currentNode[currentDigit] = nextFreeNode;
   nextFreeNode[0] = NULL;
   nextFreeNode[1] = NULL;
   nextFreeNode += (sizeof(void*) << 1);
   currentNode = patternTree;
   nodeCount++;
  }
  else
  {
   currentNode = currentNode[currentDigit];
  }
  sequenceIndex++;
 }

 free(patternTree);
 return nodeCount;
}


int main(int argc, char *argv[])
{
 printf("%u\n", LZComplexity("10100101001011101011", 1000));
 return 0;
}
person Taliadon    schedule 09.02.2011
comment
Спасибо Талиадону за то, что нашли время написать код, лично у меня нет проблем с пустыми указателями! ;) для меня ваш код выглядит вполне нормально! :D, но мне просто интересно, что, например, я написал, должен ли я получить LZ-сложность как 6 или 8?! ваш код и ручное построение дерева предполагают 8, но я читал, что должно быть 6, какие-либо комментарии по этому поводу? - person Arash; 01.03.2011
comment
если у вас есть ошибки компиляции, просто сделайте два простых приведения типа (void*) к (void **), и это должно сработать! - person Arash; 01.03.2011

1 0 01 11 10 110 00 010
Сложность последовательности равна 8, потому что разделов 8, а не 6 - 1/0/01/11/10/110/00/010

person Sanchit Gupta    schedule 17.09.2011
comment
ну, сложность LZ строки на самом деле не рассчитывается, как вы указали. Это другое, и для приведенного выше примера это 6, а не 8 :-) - person Arash; 06.10.2011
comment
ниже приведен слегка измененный код для обслуживания открытой последовательности, то есть последовательностей с нечетким последним шаблоном LZ... он решил мою проблему для расчета сложности LZ в соответствии со статьей «О сложности последовательностей Лемпеля-Зива» Али Доганаксой1,2,4 и Фарук Г¨ ологлу2,3 - person Sanchit Gupta; 16.10.2011
comment
внутренний флаг; в то время как (p_binarySequence[sequenceIndex]) { currentDigit = p_binarySequence[sequenceIndex] - 48; if (NULL == currentNode[currentDigit]) { currentNode[currentDigit] = nextFreeNode; следующий свободный узел [0] = NULL; следующий свободный узел[1] = NULL; nextFreeNode += (sizeof(void*) ‹‹ 1); текущийУзел = дерево шаблонов; количество узлов++; флаг=0; } else { currentNode = currentNode[currentDigit]; флаг=1; } индекс последовательности++; } бесплатно (дерево шаблонов); если (флаг == 0) вернуть nodeCount; иначе вернуть nodeCount+1; } - person Sanchit Gupta; 16.10.2011
comment
@Arash Я прочитал эту статью и получил сложность LZ 8 :) О сложности последовательностей Лемпеля-Зива Али Доганаксой1,2,4 и Фарук Гологлу2,3 - person Sanchit Gupta; 16.10.2011

@Араш и @Санчит Гупта: Возможно, вы запутались между сложностью LZ76 и сложностью LZ78. Тот, о котором говорит Араш, — это сложность LZ76, а другой — сложность LZ78. Вы можете обратиться к разделу 3 статьи «Оценка уровня энтропии импульсных поездов с помощью сложности Лемпеля-Зива».

person Deekshith    schedule 08.03.2012

Guillermo Valle имеет реализацию, которая создает правильные ответы (в отличие, например, от текущего кода Википедии).

Например,

Сложность 0001 равна 2: 0 001

Сложность 010 равна 3: 0 1 0

person Bjørn Kjos-Hanssen    schedule 06.07.2020

Создайте бинарное дерево, где слева 0, а справа 1. Для каждого бита попытайтесь найти последовательность в дереве. Если он есть, соедините следующий бит, промойте, повторите. Если его там нет, добавьте его в дерево и продолжайте. LZ Сложность — это общее количество путей в дереве (а не только # листовых узлов).

Кстати, это homework?

person Justin Morgan    schedule 09.02.2011
comment
Спасибо, Джастин, за разъяснение. Я до сих пор не уверен, правильно ли я понял или нет, но для примера, который я упоминаю в вопросе, если я построю дерево, я получу 8 путей (общее количество узлов в дереве минус один, корень) это правильно? Я ожидал получить 6 в качестве ответа, поскольку я только что прочитал (не уверен), что LZ-сложность должна быть 6 в этом примере! До сих пор не ясно для меня, как они вычислили это! - person Arash; 01.03.2011
comment
и кстати, это не моя домашняя работа! ;) Мне это нужно для очень странной цели, если быть более точным, я хочу найти регулярность шаблонов в передаче данных между двумя взаимодействующими функциями в приложении!!! довольно странно да? :) - person Arash; 01.03.2011

Это может быть актуально для вас. Это параллельная реализация алгоритма LZMP, который вычисляет LZ-сложность в CUDA и работает на графическом процессоре nVidia.

http://www.ariel.ac.il/sites/ratsaby/Code/LZMP.zip

person J.R.    schedule 21.03.2017
comment
можно добавить как комментарий - person jjj; 21.03.2017
comment
Ссылка, кажется, мертва. - person r.e.s.; 07.08.2020

Это должно сработать в Python (из: Kaspar, F. Schuster, H. Легко вычисляемая мера сложности пространственно-временных паттернов. Physical Review A, vol 36, n. 2, p 842.)

#!/usr/bin/python


def lz_complexity(s):
    i, k, l = 0, 1, 1
    k_max = 1
    n = len(s) - 1
    c = 1
    while True:
        if s[i + k - 1] == s[l + k - 1]:
            k = k + 1
            if l + k >= n - 1:
                c = c + 1
                break
        else:
            if k > k_max:
               k_max = k
            i = i + 1
            if i == l:
                c = c + 1
                l = l + k_max
                if l + 1 > n:
                    break
                else:
                    i = 0
                    k = 1
                    k_max = 1
            else:
                k = 1
    return c


def main():
    lz = lz_complexity('1001111011000010')
    assert lz == 6 
    print lz


if __name__ == '__main__':

    main()
person rgiglio    schedule 07.06.2015
comment
Это дает сложность 010 как 2, но она должна быть 3? - person Bjørn Kjos-Hanssen; 06.07.2020