/*
* RapidMiner
*
* Copyright (C) 2001-2011 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.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.LinkedList;
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 LinkedList<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) {
ListIterator li = this.listOfObjects.listIterator(i);
return (SearchObject) li.next();
}
/**
* This method delivers an Iterator on the list of objects of the container positioned at
* the beginning of the list.
*/
public ListIterator getListIterator() {
ListIterator li = this.listOfObjects.listIterator();
return li;
}
}