Дерево суффикса Ukkonen: процедура "canonize" неясна

Как работает функция "canonize" (приведенная ниже, из бумаги Укконена), и в частности, когда цикл while завершен? Я думаю, что значение p '- k' всегда будет меньше, чем значение p - k. Правильно или неправильно?

procedure canonize(s, (k, p)):
1. if p < k then return (s, k)
2. else
3. find the tk–transition g'(s, (k', p')) = s' from s;
4. while p' − k' <= p − k do
5.     k  = k + p' − k' + 1;
6.     s  = s';
7.     if k <= p then find the tk–transition g'(s, (k', p')) = s' from s;
8. return (s, k).

Ответы

Ответ 1

Что делает функция canonize, это то, что описано в самом конце этого сообщения SA, где мы рассматриваем такую ​​ситуацию:

enter image description here

Ситуация такова:

  • Активная точка находится в (red,'d',3), т.е. три символа в краю defg, выходящем из красного node.

  • Теперь мы следуем ссылке суффикса на зеленый node. Теоретически, наш активный node теперь (green,'d',3).

  • К сожалению, эта точка не существует, потому что край de, выходящий из зеленого node, имеет только 2 символа. Следовательно, мы применяем функцию canonize.

Он работает следующим образом:

  • Начальный характер интересующего нас ребра d. Этот символ упоминается как t k в обозначении Ukkonen. Итак, "поиск t k -edge" означает поиск края de на зеленом node.

  • Этот край имеет длину всего два символа. То есть (p' - k') == 2 в обозначениях Укконена. Но исходный край имел три символа: (p - k) == 3. Итак, <= истинно, и мы вводим цикл.

  • Мы сокращаем ребро, которое мы ищем, от def до f. Это то, что делает шаг p := p + (k' - p') + 1.

  • Мы переходим в состояние, на которое указывает ребро de, т.е. голубое состояние. Это то, что делает s := s'.

  • Так как оставшаяся часть f края не пуста (k <= p), мы идентифицируем соответствующий выходящий край (то есть край fg, выходящий из синего node). Этот шаг устанавливает k 'и p' в совершенно новые значения, поскольку теперь они относятся к строке fg, а ее длина (p '- k') теперь будет равна 2.

  • Длина оставшегося ребра f, (p - k) теперь равна 1, а длина края-кандидата fg для новой активной точки (p '- k'), равно 2. Следовательно, условие цикла

    while (p '- k') <= (p - k) do

перестает быть истинным, поэтому цикл заканчивается, и действительно, новая (и правильная) активная точка (blue,'f',1).

[На самом деле, в обозначениях Укконена конечный указатель р ребра указывает на положение конечного символа ребра, а не на следующую позицию. Следовательно, строго говоря, (p - k) равно 0, а не 1, а (p '- k') равно 1, а не 2. Но важно не абсолютное значение длины, а относительное сравнение двух разных длина.]

Несколько заключительных заметок:

  • Указатели, такие как p и k, ссылаются на позиции в исходном тексте ввода t. Это может быть довольно запутанным. Например, указатели, используемые в краю de на зеленом node, будут ссылаться на некоторую подстроку de для t, а указатели, используемые в краю fg на синем node, будут ссылаться на некоторую подстроку fg t. Хотя строка defg должна отображаться как одна непрерывная строка где-то в t, подстрока fg может отображаться и в других местах. Таким образом, указатель k края fg не обязательно конечный указатель p края de плюс один.

  • Что считается, когда мы решаем, следует ли закончить цикл, это не абсолютные позиции k или p, а длина (p - k) оставшегося ребра по сравнению с длиной (p '- k' ) текущего края-кандидата.

  • В вашем вопросе, строка 4 фрагмента кода, есть опечатка: она должна быть k' вместо k;.

Ответ 2

Мне пришлось изменить функцию канонизации, потому что она не обрабатывала вспомогательное состояние должным образом. Я добавил следующий код после 'p < k ', если:

if (s == auxiliary)
{
    s = root;
    k++;
    if (p < k)
        return;
}

Теперь он работает:)