class AveragePrecision extends AbstractRecommendationMetric<U, I> {

    @Override
    public double evaluate(Recommendation<U, I> recommendation) {
        UserIdealRelevanceModel<U, I> userRelModel = relModel.getModel(recommendation.getUser());

        int nRelItems = min(cutoff, userRelModel.getRelevantItems().size());
        if (nRelItems == 0) {
            return 0.0;
        }

        double ap = 0;
        int relCount = 0;
        int rank = 0;

        for (Tuple2od<I> pair : recommendation.getItems()) {
            rank++;
            if (userRelModel.isRelevant(pair.v1)) {
                relCount++;
                ap += relCount / (double) rank;
            }
            if (rank == cutoff) {
                break;
            }
        }

        return ap / nRelItems;
    }

}

class AveragePrecisionTest {

    private final PreferenceData<String, String> prefs;
    private final RecommendationMetric<String, String> ap;

    @Test
    public void testA() {

        Recommendation<String, String> recA = new Recommendation<>("a", Arrays.asList(
                Tuples.tuple("A", 9.0),
                Tuples.tuple("L", 8.0),
                Tuples.tuple("B", 7.0),
                Tuples.tuple("N", 6.0),
                Tuples.tuple("O", 5.0),
                Tuples.tuple("P", 4.0),
                Tuples.tuple("Q", 3.0),
                Tuples.tuple("L", 2.0),
                Tuples.tuple("C", 1.0),
                Tuples.tuple("R", 0.0)
        ));

        Assert.assertEquals(5.0 / 12.0, ap.evaluate(recA), 1e-12);
    }

}