code: @Nonnull
      public Word<I> canonicalNext(Alphabet<I> sigma) {
          int len = length();
          Object[] symbols = new Object[len];
          writeToArray(0, symbols, 0, len);
  
          int alphabetSize = sigma.size();
  
          int i = 0;
          boolean overflow = true;
          for (I sym : this) {
              int nextIdx = (sigma.getSymbolIndex(sym) + 1) % alphabetSize;
              symbols[i++] = sigma.getSymbol(nextIdx);
              if (nextIdx != 0) {
                  overflow = false;
                  break;
              }
          }
  
          while (i < len) {
              symbols[i] = getSymbol(i);
              i++;
          }
  
          if (overflow) {
              Object[] newSymbols = new Object[len + 1];
              newSymbols[0] = sigma.getSymbol(0);
              System.arraycopy(symbols, 0, newSymbols, 1, len);
              symbols = newSymbols;
          }
  
          return new SharedWord<>(symbols);
      }
docs: Retrieves the next word after this in canonical order. Figuratively speaking, if there are {@code k} alphabet
  symbols, one can think of a word of length {@code n} as an {@code n}-digit radix-{@code k} representation of
  the number. The next word in canonical order is the representation for the number represented by this word plus
  one.
  
  @param sigma
  the alphabet
  
  @return the next word in canonical order