private <T> void checkNormalized(Iterable<T> targets, Metric<T> metric) {
    for (T target1 : targets) {
      for (T target2 : targets) {
        if (target1 == target2) continue;

        double distance1 = metric.distance(target1, target2);
        assertTrue(">1", Double.compare(distance1, 1d) <= 0);
        assertTrue("<0", Double.compare(distance1, 0d) >= 0);

        double distance2 = metric.distance(target2, target1);
        assertTrue(">1", Double.compare(distance2, 1d) <= 0);
        assertTrue("<0", Double.compare(distance2, 0d) >= 0);
      }
    }
  }
  private <T> void checkSymmetric(Iterable<T> targets, Metric<T> metric) {
    for (T target1 : targets) {
      for (T target2 : targets) {
        if (target1 == target2) continue;

        double distance1 = metric.distance(target1, target2);
        double distance2 = metric.distance(target2, target1);

        assertTrue("not symmetric", Double.compare(distance1, distance2) == 0);
      }
    }
  }
  public void internalTestPerformance(Metric<double[]> metric, double[] value1, double[] value2)
      throws IOException {

    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    for (int i = 0; i < 10000000; i++) {
      metric.distance(value1, value2);
    }

    System.out.println(metric.getClass().getName() + ": " + stopWatch.meanTime());
  }