https://github.com/jonas-ellert/right-lyndon
Raw File
Tip revision: f292fd218d0edb546530aaf517923eccb79b2736 authored by jonas-ellert on 12 April 2022, 19:32:52 UTC
Update README.md
Tip revision: f292fd2
right-lyndon-extension-improved.hpp
#pragma once

#include <cmath>
#include <cstdint>
#include <cstring>
#include <limits>
#include <vector>

// at all times, by design of the program, it holds i < j

template <std::integral intX = uint32_t>
auto right_lyndon_extension_improved(std::integral auto const* text,
                                     size_t const n) {
  //
  // the integer type has to be wide enough!
  if (n > std::numeric_limits<intX>::max()) {
    std::abort();
  }

  // the result: NSS and PSS array, each annotated with LCEs
  struct xss_type {
    intX nss;
    intX pss;
    intX nss_lce = 0;
    intX pss_lce = 0;
  };
  std::vector<xss_type> res(n, {(intX)n, (intX)n});

  // auxiliary information required by the algorithm
  struct aux_type {
    intX max_lce = 0;
    intX left = 0;
  };
  std::vector<aux_type> aux(n + 1);

  // access functions (syntactic sugar)
  auto nss = [&res](size_t const idx) -> intX& { return res[idx].nss; };
  auto nlce = [&res](size_t const idx) -> intX& { return res[idx].nss_lce; };
  auto pss = [&res](size_t const idx) -> intX& { return res[idx].pss; };
  auto plce = [&res](size_t const idx) -> intX& { return res[idx].pss_lce; };
  auto max_lce = [&aux](size_t const idx) -> intX& { return aux[idx].max_lce; };
  auto left = [&aux](size_t const idx) -> intX& { return aux[idx].left; };

  // add sentinel symbol at the end
  auto S = [&](size_t const idx) {
    return (idx < n) ? (int64_t)text[idx] : std::numeric_limits<int64_t>::min();
  };

  // update the maximum lce of position j if necessary
  auto update_max_lce = [&](intX i, intX j, intX lce) {
    // check if this is a new maximum, or if this is the first lce(_,j)
    if (lce > max_lce(j) || left(j) == 0) {
      max_lce(j) = lce;
      left(j) = i;
    }
  };

  // We assign each NSS (respectively PSS) value together with its associated
  // LCE value. For each assignment, we check if this is the maximum LCE value
  // with right-hand side j, and update the max-lce if necessary.
  auto assign_pss = [&](intX i, intX j, intX lce) {
    pss(j) = i;
    plce(j) = lce;
    update_max_lce(i, j, lce);
  };
  auto assign_nss = [&](intX i, intX j, intX lce) {
    nss(i) = j;
    nlce(i) = lce;
    update_max_lce(i, j, lce);
  };

  // This is the extension technique described in the paper.
  auto extend = [&](intX const i, intX const j, intX& lce) {
    // If S(i) and S(j) are different, then we immediately return with LCE 0
    if (S(i) != S(j)) {
      lce = 0;
      return;
    }

    intX const d = j - i;
    intX rr = j + std::max((intX)1, max_lce(j));  // qj in the paper
    intX lr = rr - d;                             // qi in the paper
    intX extend = 0;

    while (S(lr) == S(rr)) {
      intX rl = left(rr);
      intX rlce = max_lce(rr);

      intX ll = rl - d;
      intX llce;

      // case 1:
      if (ll == i && lr == j) {  // implies rr = j + d
        llce = rlce + d;
      }
      // case 2:
      else if (nss(ll) == lr) {
        llce = nlce(ll);
      } else if (pss(lr) == ll) {
        llce = plce(lr);
      }
      // case 3:
      else {
        llce = plce(lr);
        rlce = nlce(pss(lr) + d);
      }

      extend = std::min(llce, rlce);
      if (extend < max_lce(rr)) break;

      extend = 0;
      rr = rr + std::max((intX)1, max_lce(rr));
      lr = rr - d;
    }

    lce = rr - j + extend;
  };

  // This is the main loop of the algorithm, see algorithm LceLyn in the paper
  for (int64_t i = n - 1; i >= 0; --i) {
    intX j = i + 1;
    intX lce = (S(i) == S(j)) ? (max_lce(j + 1) + 1) : ((intX)0);

    while (S(j + lce) > S(i + lce)) {
      assign_pss(i, j, lce);

      if (lce > nlce(j)) {
        lce = nlce(j);
        j = nss(j);
      } else if (lce < nlce(j)) {
        j = nss(j);
      } else {
        j = nss(j);
        extend(i, j, lce);
      }
    }

    assign_nss(i, j, lce);
  }

  return res;
}
back to top