code: public static MutableFst composeWithPrecomputed(MutableFst fst1, PrecomputedComposeFst fst2, boolean useSorted, boolean trimOutput) {
      fst1.throwIfInvalid();
      if (useSorted) {
        if (fst1.getOutputSymbols() != fst2.getFstInputSymbolsAsFrozen() &&
            fst1.getOutputSymbols() != fst2.getFst().getInputSymbols()) {
          throw new IllegalArgumentException("When using the precomputed and useSorted optimization, you must have " +
              "the outer's output symbol be the same symbol table as the inner's input");
        }
      }
      Semiring semiring = fst2.getSemiring();
  
      augment(AugmentLabels.OUTPUT, fst1, semiring, fst2.getEps1(), fst2.getEps2());
      if (useSorted) {
        ArcSort.sortByOutput(fst1);
      }
      ImmutableFst filter = fst2.getFilterFst();
      MutableFst tmp = Compose.doCompose(fst1, filter, semiring, useSorted);
      if (useSorted) {
        ArcSort.sortByOutput(tmp);
      }
      MutableFst res = Compose.doCompose(tmp, fst2.getFst(), semiring, useSorted);
      // definitionally the output of compose should be trimmed, but if you don't care, you can save some cpu
      if (trimOutput) {
        Connect.apply(res);
      }
      return res;
    }
docs: Executes a compose of fst1 o fst2, with fst2 being a precomputed/preprocessed fst (for performance reasons)
  @param fst1 outer fst
  @param fst2 inner fst
  @param useSorted if true, then performance will be faster; NOTE fst1 must be sorted by OUTPUT labels
  @param trimOutput if true, then output will be trimmed before returning
  @return