class InformationContentComputation {

  public Map<TermId, Double> computeInformationContent(Map<TermId, Collection<TermId>> termLabels) {
    LOGGER.info(
        "Computing IC of {} terms using {} labels...",
            ontology.countAllTerms(), termLabels.values().stream().mapToInt(Collection::size).sum()
        );

    // Build mapping from TermId -> absolute frequency
    // Ought to use ontology.getRootTermId() ?
    final TermId root = ontology.getRootTermId();//TermId.of("HP:0000118");

    final Map<TermId, Integer> termToFrequency = new HashMap<>();
    for (TermId termId : ontology.getNonObsoleteTermIds()) {
      termToFrequency.put(termId, 0);
    }
    for (Entry<TermId, Collection<TermId>> e : termLabels.entrySet()) {
      termToFrequency.put(e.getKey(), e.getValue().size());
    }

    // Compute information content for each TermId
    final int maxFreq = termToFrequency.get(root);
    final Map<TermId, Double> termToInformationContent = caculateInformationContent(maxFreq, termToFrequency);

    // Fix terms with IC of zero, set it to IC of root
    int countIcZero = 0;
    final double dummyIc = -Math.log(1 / (double) maxFreq);

    for (Term t : ontology.getTerms()) {
      if (t.isObsolete()) {
        continue;
      }
      if (!termToFrequency.containsKey(t.getId())) {
        ++countIcZero;
        termToInformationContent.put(t.getId(), dummyIc);
      }
    }

    if (countIcZero > 0) {
      LOGGER.warn(
          "Frequency of {} non-obsolete terms was zero! Their IC has been set to {} =  - log(1 / {}).", countIcZero, dummyIc, maxFreq);
    }
    LOGGER.info("Computing IC is complete.");

    return termToInformationContent;
  }

  public  InformationContentComputation(Ontology ontology);

}