code: private double computeFinalWeight(final int outputStateId,
                                      final DetStateTuple targetTuple,
                                      Deque<DetElement> finalQueue) {
      UnionWeight<GallicWeight> result = this.unionSemiring.zero();
      for (DetElement detElement : targetTuple.getElements()) {
        State inputState = this.getInputStateForId(detElement.inputStateId);
        if (this.semiring.isZero(inputState.getFinalWeight())) {
          continue; // not final so it wont contribute
        }
        UnionWeight<GallicWeight> origFinal = UnionWeight.createSingle(GallicWeight.createEmptyLabels(
          inputState.getFinalWeight()));
        result = this.unionSemiring.plus(result, this.unionSemiring.times(detElement.residual, origFinal));
      }
      if (this.unionSemiring.isZero(result)) {
        return this.semiring.zero();
      }
      if (result.size() == 1 && result.get(0).getLabels().isEmpty()) {
        // by good fortune the residual is just a weight, no path to expand so this new state can have a final weight
        // set now! with nothing to enqueue
        return result.get(0).getWeight();
      }
      // this state can't be a final state because we have more path to emit so defer until later; we know that we cant
      // have any duplicate elements in the finalQueue since we only call computeFinalWeight once for each outputStateId
      finalQueue.addLast(new DetElement(outputStateId, result));
      return this.semiring.zero(); // since we're deferring this weight can't be a final weight
    }
docs: _this_ new outState a final state, and instead we queue it into a separate queue for later expansion