/* * BioJava development code * * This code may be freely distributed and modified under the * terms of the GNU Lesser General Public Licence. This should * be distributed with the code. If you do not have a copy, * see: * * http://www.gnu.org/copyleft/lesser.html * * Copyright for this code is held jointly by the individual * authors. These should be listed in @author doc comments. * * For more information on the BioJava project and its aims, * or to join the biojava-l mailing list, visit the home page * at: * * http://www.biojava.org/ * */ package org.biojavax.ga.util; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; /** *
Inspred by the BioJava Distribution objects the WeightedSet is a map from * a Key to a Weight. Unlike Distributions the Keys do not have to be Symbols. * In the GA package the WeightedMap is useful for sampling Organisms according * to their fitness.
* *When Symbols are added or their weights are set then the weights are internally * normalized to 1
* * @author Mark Schreiber * @version 1.0 * @since 1.5 */ public class WeightedSet extends AbstractSet implements java.io.Serializable{ private HashMap key2Weight; double totalWeight; public WeightedSet() { key2Weight = new HashMap(); } /** * Converts the Set to a map from keyObjects
to Double
* weights.
* @return a Map with all the key-weight mappings. Weights are not normalized in this map.
*/
public Map asMap(){
return key2Weight;
}
/**
* Randomly samples an Object
from the Set
according
* to its weight.
* @return the Object sampled.
*/
public Object sample(){
double p = Math.random();
for (Iterator i = this.iterator(); i.hasNext(); ) {
Object o = i.next();
double weight = getWeight(o);
p -= weight;
if(p <= 0.0){
return o;
}
}
throw new org.biojava.bio.BioError("Cannot sample an object, does this set contain any objects?");
}
/**
* Determines the normalized weight for o
* @param o the Object
you want to know the weight of
* @return the normalized weight
* @throws NoSuchElementException if o
is not found in this set
*/
public double getWeight(Object o) throws NoSuchElementException{
if(!( key2Weight.containsKey(o)))
throw new NoSuchElementException(o+" not found in this WeightedSet");
Double d = (Double)key2Weight.get(o);
if(totalWeight == 0.0)
return 0.0;
return d.doubleValue() / totalWeight;
}
/**
* The total weight that has been added to this Set.
* @return the total weight (the value that can be used for normalizing)
*/
protected double getTotalWeight(){
return totalWeight;
}
/**
* Sets the weight of an Object
. If the Object
is
* not in this Set
then it is added.
* @param o the Object
* @param w the weight.
* @throws IllegalArgumentException if w
is < 0.0
*/
public void setWeight(Object o, double w){
if(w < 0.0){
throw new IllegalArgumentException("Weight must be >= 0.0");
}
if(key2Weight.containsKey(o)){
remove(o);
}
totalWeight += w;
key2Weight.put(o, Double.valueOf(w));
}
public boolean contains(Object o) {
return key2Weight.containsKey(o);
}
public boolean remove(Object o) {
if(key2Weight.containsKey(o)){
totalWeight -= ((Double)key2Weight.get(o)).doubleValue();
key2Weight.remove(o);
return true;
}
return false;
}
public boolean isEmpty() {
return key2Weight.isEmpty();
}
public boolean retainAll(Collection c) {
boolean b = false;
Collection toRemove = new ArrayList();
for (Iterator i = iterator(); i.hasNext(); ) {
Object item = i.next();
if(c.contains(item) == false){
b = true;
toRemove.add(item);
}
}
removeAll(toRemove);
return b;
}
/**
* Adds a new Object
with a weight of zero. Equivalent to
* setWeight(o, 0.0);
* @param o the object to add.
* @return true if this Object has not been added before.
*/
public boolean add(Object o) {
boolean b = !(key2Weight.containsKey(o));
setWeight(o, 0.0);
return b;
}
public int size() {
return key2Weight.size();
}
public boolean containsAll(Collection c) {
if(size() == 0)
return false;
for (Iterator i = iterator(); i.hasNext(); ) {
Object item = i.next();
if(!(key2Weight.containsKey(item))){
return false;
}
}
return true;
}
public Object[] toArray() {
Object[] o = new Object[size()];
int j = 0;
for (Iterator i = iterator(); i.hasNext(); ) {
o[j++] = i.next();
}
return o;
}
public void clear() {
key2Weight = new HashMap();
totalWeight = 0.0;
}
/**
* Returns an unmodifiable iterator over the keys of the set.
* @return an Iterator
*/
public Iterator iterator() {
return Collections.unmodifiableSet(key2Weight.keySet()).iterator();
}
public boolean addAll(Collection c) {
boolean b = false;
for (Iterator i = c.iterator(); i.hasNext(); ) {
Object item = i.next();
if(!(key2Weight.containsKey(item)))
b = true;
add(item);
}
return b;
}
}