code: private static void calculateClosure(Fst fst, State state, HashMap<Integer,Double>[] closure, Semiring semiring, int iEps, int oEps) {
  
      for (int j = 0; j < state.getArcCount(); j++) {
        Arc arc = state.getArc(j);
        if ((arc.getIlabel() != iEps) || (arc.getOlabel() != oEps)) {
          continue;
        }
        int nextStateId = arc.getNextState().getId();
        if (closure[nextStateId] == null) {
          calculateClosure(fst, arc.getNextState(), closure, semiring, iEps, oEps);
        }
        HashMap<Integer,Double> closureEntry = closure[nextStateId];
        if (closureEntry != null) {
          for (Integer pathFinalStateIndex : closureEntry.keySet()) {
            State pathFinalState = fst.getState(pathFinalStateIndex);
            Double prevPathWeight = getPathWeight(arc.getNextState(), pathFinalState, closure);
            Preconditions.checkNotNull(prevPathWeight, "prev arc %s never set in closure", arc);
            double newPathWeight = semiring.times(prevPathWeight, arc.getWeight());
            add(state, pathFinalState, newPathWeight, closure, semiring);
          }
        }
        add(state, arc.getNextState(), arc.getWeight(), closure, semiring);
      }
    }
docs: Calculate the epsilon closure