TreeSet<FCPair<Double, DBID>> minhotset = new TreeSet<FCPair<Double, DBID>>();
TreeSet<FCPair<Double, DBID>> maxhotset = new TreeSet<FCPair<Double, DBID>>(Collections.reverseOrder());
int randomsize = (int) Math.max(25, Math.pow(database.size(), 0.2));
double rprob = ((double) randomsize) / size;
ArrayModifiableDBIDs randomset = DBIDUtil.newArray(randomsize);
Iterator<DBID> iter = database.iterDBIDs();
if(!iter.hasNext()) {
throw new IllegalStateException(ExceptionMessages.DATABASE_EMPTY);
}
DBID firstid = iter.next();
minhotset.add(new FCPair<Double, DBID>(Double.MAX_VALUE, firstid));
maxhotset.add(new FCPair<Double, DBID>(Double.MIN_VALUE, firstid));
while(iter.hasNext()) {
DBID id1 = iter.next();
// generate candidates for min distance.
ArrayList<FCPair<Double, DBID>> np = new ArrayList<FCPair<Double, DBID>>(k * 2 + randomsize * 2);
for(FCPair<Double, DBID> pair : minhotset) {
DBID id2 = pair.getSecond();
// skip the object itself
if(id1.compareTo(id2) == 0) {
continue;
}
double d = distFunc.distance(id1, id2).doubleValue();
np.add(new FCPair<Double, DBID>(d, id1));
np.add(new FCPair<Double, DBID>(d, id2));
}
for(DBID id2 : randomset) {
double d = distFunc.distance(id1, id2).doubleValue();
np.add(new FCPair<Double, DBID>(d, id1));
np.add(new FCPair<Double, DBID>(d, id2));
}
minhotset.addAll(np);
shrinkHeap(minhotset, k);
// generate candidates for max distance.
ArrayList<FCPair<Double, DBID>> np2 = new ArrayList<FCPair<Double, DBID>>(k * 2 + randomsize * 2);
for(FCPair<Double, DBID> pair : minhotset) {
DBID id2 = pair.getSecond();
// skip the object itself
if(id1.compareTo(id2) == 0) {
continue;
}
double d = distFunc.distance(id1, id2).doubleValue();
np2.add(new FCPair<Double, DBID>(d, id1));
np2.add(new FCPair<Double, DBID>(d, id2));
}
for(DBID id2 : randomset) {
double d = distFunc.distance(id1, id2).doubleValue();
np.add(new FCPair<Double, DBID>(d, id1));
np.add(new FCPair<Double, DBID>(d, id2));
}
maxhotset.addAll(np2);
shrinkHeap(maxhotset, k);
// update random set
if(randomset.size() < randomsize) {
randomset.add(id1);
}
else if(rnd.nextDouble() < rprob) {
randomset.set((int) Math.floor(rnd.nextDouble() * randomsize), id1);
}
}
return new DoubleMinMax(minhotset.first().getFirst(), maxhotset.first().getFirst());
}