private static int @NotNull [] getBestMatchingAlignment(@NotNull final IntList subLines1,
                                                          @NotNull final IntList subLines2,
                                                          @NotNull final List<? extends Line> lines1,
                                                          @NotNull final List<? extends Line> lines2) {
    assert subLines1.size() < subLines2.size();
    final int size = subLines1.size();

    final int[] comb = new int[size];
    final int[] best = new int[size];
    for (int i = 0; i < size; i++) {
      best[i] = i;
    }

    // find a combination with maximum weight (maximum number of equal lines)
    new Object() {
      int bestWeight = 0;

      public void run() {
        combinations(0, subLines2.size() - 1, 0);
      }

      private void combinations(int start, int n, int k) {
        if (k == size) {
          processCombination();
          return;
        }

        for (int i = start; i <= n; i++) {
          comb[k] = i;
          combinations(i + 1, n, k + 1);
        }
      }

      private void processCombination() {
        int weight = 0;
        for (int i = 0; i < size; i++) {
          int index1 = subLines1.getInt(i);
          int index2 = subLines2.getInt(comb[i]);
          if (lines1.get(index1).equals(lines2.get(index2))) weight++;
        }

        if (weight > bestWeight) {
          bestWeight = weight;
          System.arraycopy(comb, 0, best, 0, comb.length);
        }
      }
    }.run();

    return best;
  }
private static int @NotNull [] getBestMatchingAlignment(@NotNull final IntList subLines1,
                                                          @NotNull final IntList subLines2,
                                                          @NotNull final List<? extends Line> lines1,
                                                          @NotNull final List<? extends Line> lines2)