class BinaryClassificationMetrics extends AbstractMetrics<BinaryClassificationMetricValues> {

    @Override public BinaryClassificationMetricValues scoreAll(Iterator<LabelPair<Double>> iter) {
        long tp = 0;
        long tn = 0;
        long fp = 0;
        long fn = 0;
        double rocauc = Double.NaN;

        // for ROC AUC calculation
        long pos = 0;
        long neg = 0;
        PriorityQueue<Pair<Double, Double>> queue = new PriorityQueue<>(Comparator.comparingDouble(Pair::getKey));

        while (iter.hasNext()) {
            LabelPair<Double> e = iter.next();

            double prediction = e.getPrediction();
            double truth = e.getTruth();

            if (prediction != negativeClsLb && prediction != positiveClsLb)
                throw new UnknownClassLabelException(prediction, positiveClsLb, negativeClsLb);
            if (truth != negativeClsLb && truth != positiveClsLb)
                throw new UnknownClassLabelException(truth, positiveClsLb, negativeClsLb);

            if (truth == positiveClsLb && prediction == positiveClsLb) tp++;
            else if (truth == positiveClsLb && prediction == negativeClsLb) fn++;
            else if (truth == negativeClsLb && prediction == negativeClsLb) tn++;
            else if (truth == negativeClsLb && prediction == positiveClsLb) fp++;

            if (enableROCAUC) {
                queue.add(new Pair<>(prediction, truth));

                if (truth == positiveClsLb)
                    pos++;
                else if (truth == negativeClsLb)
                    neg++;
                else
                    throw new UnknownClassLabelException(truth, positiveClsLb, negativeClsLb);
            }

        }

        if (enableROCAUC)
            rocauc = ROCAUC.calculateROCAUC(queue, pos, neg, positiveClsLb);

        return new BinaryClassificationMetricValues(tp, tn, fp, fn, rocauc);
    }

}