protected List<Entry<OWLClassExpression, Integer>> sortByValues(
      Map<OWLClassExpression, Integer> map, final boolean useHierachy) {
    List<Entry<OWLClassExpression, Integer>> entries =
        new ArrayList<Entry<OWLClassExpression, Integer>>(map.entrySet());
    final ClassHierarchy hierarchy = reasoner.getClassHierarchy();

    Collections.sort(
        entries,
        new Comparator<Entry<OWLClassExpression, Integer>>() {

          @Override
          public int compare(
              Entry<OWLClassExpression, Integer> o1, Entry<OWLClassExpression, Integer> o2) {
            int ret = o2.getValue().compareTo(o1.getValue());
            // if the score is the same, than we optionally also take into account the subsumption
            // hierarchy
            if (ret == 0 && useHierachy) {
              if (hierarchy != null) {
                if (hierarchy.contains(o1.getKey()) && hierarchy.contains(o2.getKey())) {
                  if (hierarchy.isSubclassOf(o1.getKey(), o2.getKey())) {
                    ret = -1;
                  } else if (hierarchy.isSubclassOf(o2.getKey(), o1.getKey())) {
                    ret = 1;
                  } else {
                    // we use the depth in the class hierarchy as third ranking property
                    //								int depth1 = hierarchy.getDepth2Root(o1.getKey());
                    //								int depth2 = hierarchy.getDepth2Root(o2.getKey());
                    //								ret = depth1 - depth2;
                  }
                }
              }
            }

            return ret;
          }
        });
    return entries;
  }
  @Override
  public void start() {
    logger.info(
        "Started learning of "
            + axiomType.getName()
            + " axioms for "
            + OWLAPIUtils.getPrintName(entityToDescribe.getEntityType())
            + " "
            + entityToDescribe.toStringID()
            + "...");
    startTime = System.currentTimeMillis();

    currentlyBestAxioms = new TreeSet<EvaluatedAxiom<T>>();

    popularity = reasoner.getPopularity(entityToDescribe);
    if (popularity == 0) {
      logger.warn(
          "Cannot make "
              + axiomType.getName()
              + " axiom suggestions for empty "
              + OWLAPIUtils.getPrintName(entityToDescribe.getEntityType())
              + " "
              + entityToDescribe.toStringID());
      return;
    }

    if (returnOnlyNewAxioms) {
      getExistingAxioms();
    }

    if (useSampling) {
      generateSample();
    } else {
      qef = ksQef;
      reasoner = ksReasoner;
    }

    progressMonitor.learningStarted(axiomType);
    try {
      learnAxioms();
    } catch (Exception e) {
      progressMonitor.learningFailed(axiomType);
      throw e;
    } finally {
      progressMonitor.learningStopped(axiomType);
    }

    logger.info(
        "...finished learning of "
            + axiomType.getName()
            + " axioms for "
            + OWLAPIUtils.getPrintName(entityToDescribe.getEntityType())
            + " "
            + entityToDescribe.toStringID()
            + " in {}ms.",
        (System.currentTimeMillis() - startTime));
    if (this instanceof ObjectPropertyCharacteristicsAxiomLearner) {
      logger.info("Suggested axiom: " + currentlyBestAxioms.first());
    } else {
      logger.info("Found " + currentlyBestAxioms.size() + " axiom candidates.");
      if (!currentlyBestAxioms.isEmpty()) {
        logger.info("Best axiom candidate is " + currentlyBestAxioms.first());
      }
    }
  }