/* Copyright 2009-2016 David Hadka * * This file is part of the MOEA Framework. * * The MOEA Framework is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * The MOEA Framework is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>. */ package org.moeaframework.util.statistics; import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; /** * Abstract class for implementing ordinal (rank-based) statistical tests. * Methods are provided for storing {@link RankedObservation} objects and * updating their ranks. */ public abstract class OrdinalStatisticalTest implements StatisticalTest { /** * Compares two {@code RankedObservation} objects based on their value. */ private static class ObservationComparator implements Comparator<RankedObservation>, Serializable { private static final long serialVersionUID = 284381611483212771L; @Override public int compare(RankedObservation o1, RankedObservation o2) { if (o1.getValue() < o2.getValue()) { return -1; } else if (o1.getValue() > o2.getValue()) { return 1; } else { return 0; } } } /** * The number of groups being tested. */ protected final int numberOfGroups; /** * The comparator used for ordering observations. */ protected final Comparator<RankedObservation> comparator; /** * Collection of all ranked observations added to this test. */ protected final List<RankedObservation> data; /** * Constructs a new ordinal (rank-based) statistical test for the specified * number of groups. * * @param numberOfGroups the number of groups being tested */ public OrdinalStatisticalTest(int numberOfGroups) { this(numberOfGroups, new ObservationComparator()); } /** * Constructs a new ordinal (rank-based) statistical test for the specified * number of groups and the comparator for ordering observations. * * @param numberOfGroups the number of groups being tested * @param comparator the comparator for ordering observations */ public OrdinalStatisticalTest(int numberOfGroups, Comparator<RankedObservation> comparator) { super(); this.numberOfGroups = numberOfGroups; this.comparator = comparator; data = new ArrayList<RankedObservation>(); } /** * Adds a new observation with the specified value and group. * * @param value the value of the new observation * @param group the group to which the new observation belongs */ protected void add(double value, int group) { if ((group < 0) || (group >= numberOfGroups)) { throw new IllegalArgumentException(); } data.add(new RankedObservation(value, group)); } /** * Adds several new observations to the specified group. * * @param values the values of the new observations * @param group the group to which the new observations belong */ protected void addAll(double[] values, int group) { for (double value : values) { add(value, group); } } /** * Sorts the observations using the {@code comparator} and assigns ranks. */ protected void update() { Collections.sort(data, comparator); int i = 0; while (i < data.size()) { int j = i + 1; double rank = i + 1; while ((j < data.size()) && (data.get(i).getValue() == data.get(j).getValue())) { rank += j + 1; j++; } rank /= j - i; for (int k = i; k < j; k++) { data.get(k).setRank(rank); } i = j; } } /** * Returns the number of observations used in this test. * * @return the number of observations used in this test */ public int size() { return data.size(); } /** * Returns the number of groups being tested. * * @return the number of groups being tested */ public int getNumberOfGroups() { return numberOfGroups; } /** * Returns the comparator used by this test to order observations. * * @return the comparator used by this test to order observations */ public Comparator<RankedObservation> getComparator() { return comparator; } }