/** * Copyright (C) 2001-2017 by RapidMiner and the contributors * * Complete list of developers available at our web site: * * http://rapidminer.com * * This program is free software: you can redistribute it and/or modify it under the terms of the * GNU Affero General Public License as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * This program 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 * Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License along with this program. * If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.operator.preprocessing.outlier; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import com.rapidminer.tools.Tools; /** * <p> * This class represents a container for objects within a given distance from another object. * </p> * * <p> * It is a simple data structure with associated query and setting methods enabling a linked list of * all distance-Containers for all objects in a search Room. As most objects in a SearchSpace are * expected to be at different distances to each other, only a small number of objects is likely to * be linked to a single distance Container. However, in very dense clusters the number can increase * significantly. * </p> * * @author Stephan Deutsch, Ingo Mierswa */ public class KdistanceContainer { /** * The value for the distance of the container, e.g. containing all objects of _this_ distance * from another object. */ private double distance; /** * The SearchObject to which this distance container is associated, this is intended to be a * backward reference in case we look at a container and want to know what the information it * holds is related too. This might never be used, but implemented just in case. */ // private SearchObject distanceAssociatedObject; /** * Representing the number of objects in the distance container (e.g. the cardinality of the set * of objects in distance to the associated SearchObject). */ private int numberOfObjects; /** * This List contains the objects in the container (all objects within distance from the * associated SearchObject. */ private List<SearchObject> listOfObjects; /** * This constructor creates a container for an associated SearchObject so (which has to be * referenced) and sets the other aspects of the contained data to zero; it also creates a list * of Objects. */ public KdistanceContainer(SearchObject so) { this.listOfObjects = new ArrayList<SearchObject>(); // construct a new listOfObjects // this.distanceAssociatedObject = so; // set the container to associate the SearchObject so this.setDistance(0); // set distance to zero (as we do not yet have any object associated this.setNumberOfObjects(0); // accordingly the number of objects is zero as well } /** * Provides the distance of the container as an integer value. */ public double getDistance() { return this.distance; } /** * Sets the distance of the container to dist (double type value). * * @param dist */ public void setDistance(double dist) { this.distance = dist; } /** * Gives the number of objects in the container (e.g. which are actually in the list, but * without the need to ask the list itself about its size). */ public int getNumberOfObjects() { return this.numberOfObjects; } /** * Sets the number of objects in the container to (integer) number. This should only be used * carefully as the process to add an object to the container takes care of revising the number * of objects value itself. * * @param number */ private void setNumberOfObjects(int number) { this.numberOfObjects = number; } /** * <p> * Adds a SearchObject to the container. * </p> * * <p> * Attention: As you do this, it has to be checked, if the distance between the associated * SearchObject and the object added to the container is equal to the distance of the objects * already in the container. * </p> * * <p> * To achieve this, the method checks if the distance delivered as a sanity check parameter is * equal to the distance of the container; if yes, the object is added, else not. A boolean * state on the success is returned. * </p> * * <p> * if the container is empty, e.g. the first object is added, no checks are necessary and hence * the distance check against the initial zero value is not performed thus not preventing the * addition of the object. * </p> * * <p> * It is recommended to e.g. add an object <i>so</i> to the list of the objects of a container * associated to an object <i>soA</i> with the following process: * </p> * * <p> * KdistanceContainer.addObject(so, soA.getDistance(so)); * </p> */ public boolean addObject(SearchObject so, double dist) { // first, check if the container is empty, in this case the object can be added // without additional checks: if (this.listOfObjects.size() == 0) { this.listOfObjects.add(so); this.setDistance(dist); this.setNumberOfObjects(this.listOfObjects.size()); return true; } else { // in the other case (container is not empty) if (Tools.isEqual(this.getDistance(), dist)) { // check if distance of container is // equal to dist of added object this.listOfObjects.add(so); // if yes, then add it this.setDistance(dist); this.setNumberOfObjects(this.listOfObjects.size()); return true; } else { // if the distances are not equal, do not add the object and return false return false; } } } /** * Returns an object from the list of objects in the container at position i (check needed if * this returns the appropriate object, as internally, an iterator is started at position i in * the list and the next() element is delivered back...). * * @param i */ public SearchObject getObject(int i) { return listOfObjects.get(i); } /** * This method delivers an Iterator on the list of objects of the container positioned at the * beginning of the list. */ public ListIterator<SearchObject> getListIterator() { return listOfObjects.listIterator(); } }