/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.support.math;
import freenet.node.Location;
import freenet.support.SimpleFieldSet;
/**
* @author robert
*
* A filter on BootstrappingDecayingRunningAverage which makes it aware of the circular keyspace.
*/
public final class DecayingKeyspaceAverage implements RunningAverage, Cloneable {
private static final long serialVersionUID = 5129429614949179428L;
/**
'avg' is the normalized average location, note that the the reporting bounds are (-2.0, 2.0) however.
*/
BootstrappingDecayingRunningAverage avg;
/**
*
* @param defaultValue
* @param maxReports
* @param fs
*/
public DecayingKeyspaceAverage(double defaultValue, int maxReports, SimpleFieldSet fs) {
avg = new BootstrappingDecayingRunningAverage(defaultValue, -2.0, 2.0, maxReports, fs);
}
/**
*
* @param a
*/
public DecayingKeyspaceAverage(BootstrappingDecayingRunningAverage a) {
//check the max/min values? ignore them?
avg = a.clone();
}
@Override
public synchronized DecayingKeyspaceAverage clone() {
// Override clone() for deep copy.
// Implement Cloneable to shut up findbugs.
return new DecayingKeyspaceAverage(avg);
}
/**
*
* @return
*/
@Override
public synchronized double currentValue() {
return avg.currentValue();
}
/**
*
* @param d
*/
@Override
public synchronized void report(double d) {
if((d < 0.0) || (d > 1.0))
//Just because we use non-normalized locations doesn't mean we can accept them.
throw new IllegalArgumentException("Not a valid normalized key: " + d);
double superValue = avg.currentValue();
double thisValue = Location.normalize(superValue);
double diff = Location.change(thisValue, d);
double toAverage = (superValue + diff);
/*
To gracefully wrap around the 1.0/0.0 threshold we average over (or under) it, and simply normalize the result when reporting a currentValue
---example---
d=0.2; //being reported
superValue=1.9; //already wrapped once, but at 0.9
thisValue=0.9; //the normalized value of where we are in the keyspace
diff = +0.3; //the diff from the normalized values; Location.change(0.9, 0.2);
avg.report(2.2);//to successfully move the average towards the closest route to the given value.
*/
avg.report(toAverage);
double newValue = avg.currentValue();
if(newValue < 0.0 || newValue > 1.0)
avg.setCurrentValue(Location.normalize(newValue));
}
@Override
public synchronized double valueIfReported(double d) {
if((d < 0.0) || (d > 1.0))
throw new IllegalArgumentException("Not a valid normalized key: " + d);
double superValue = avg.currentValue();
double thisValue = Location.normalize(superValue);
double diff = Location.change(thisValue, d);
return Location.normalize(avg.valueIfReported(superValue + diff));
}
@Override
public synchronized long countReports() {
return avg.countReports();
}
/**
*
* @param d
*/
@Override
public void report(long d) {
throw new IllegalArgumentException("KeyspaceAverage does not like longs");
}
/**
*
* @param maxReports
*/
public synchronized void changeMaxReports(int maxReports) {
avg.changeMaxReports(maxReports);
}
/**
*
* @param shortLived
* @return
*/
public synchronized SimpleFieldSet exportFieldSet(boolean shortLived) {
return avg.exportFieldSet(shortLived);
}
///@todo: make this a junit test
/**
*
* @param args
*/
public static void main(String[] args) {
DecayingKeyspaceAverage a = new DecayingKeyspaceAverage(0.9, 10, null);
a.report(0.9);
for(int i = 10; i != 0; i--) {
a.report(0.2);
System.out.println("<-0.2-- current=" + a.currentValue());
}
for(int i = 10; i != 0; i--) {
a.report(0.8);
System.out.println("--0.8-> current=" + a.currentValue());
}
System.out.println("--- positive wrap test ---");
for(int wrap = 3; wrap != 0; wrap--) {
System.out.println("wrap test #" + wrap);
for(int i = 10; i != 0; i--) {
a.report(0.25);
System.out.println("<-0.25- current=" + a.currentValue());
}
for(int i = 10; i != 0; i--) {
a.report(0.5);
System.out.println("--0.5-> current=" + a.currentValue());
}
for(int i = 10; i != 0; i--) {
a.report(0.75);
System.out.println("-0.75-> current=" + a.currentValue());
}
for(int i = 10; i != 0; i--) {
a.report(1.0);
System.out.println("<-1.0-- current=" + a.currentValue());
}
}
System.out.println("--- negative wrap test ---");
a = new DecayingKeyspaceAverage(0.2, 10, null);
a.report(0.2);
for(int wrap = 3; wrap != 0; wrap--) {
System.out.println("negwrap test #" + wrap);
for(int i = 10; i != 0; i--) {
a.report(0.75);
System.out.println("-0.75-> current=" + a.currentValue());
}
for(int i = 10; i != 0; i--) {
a.report(0.5);
System.out.println("<-0.5-- current=" + a.currentValue());
}
for(int i = 10; i != 0; i--) {
a.report(0.25);
System.out.println("<-0.25- current=" + a.currentValue());
}
for(int i = 10; i != 0; i--) {
a.report(1.0);
System.out.println("--1.0-> current=" + a.currentValue());
}
}
}
}