// construct the relation Matrix of the ec-graph
Matrix E = new Matrix(ids.size(), ids.size());
KNNHeap<D> heap = new KNNHeap<D>(k);
for(int i = 0; i < ids.size(); i++) {
final DBID id = ids.get(i);
final double val = relation.get(id).doubleValue(1);
assert (heap.size() == 0);
for(int j = 0; j < ids.size(); j++) {
if(i == j) {
continue;
}
final DBID n = ids.get(j);
final double e;
final D distance = distFunc.distance(id, n);
heap.add(distance, n);
double dist = distance.doubleValue();
if(dist == 0) {
logger.warning("Zero distances are not supported - skipping: " + id + " " + n);
e = 0;
}
else {
double diff = Math.abs(val - relation.get(n).doubleValue(1));
double exp = Math.exp(Math.pow(diff, alpha));
// Implementation note: not inverting exp worked a lot better.
// Therefore we diverge from the article here.
e = exp / dist;
}
E.set(j, i, e);
}
// Convert kNN Heap into DBID array
ModifiableDBIDs nids = DBIDUtil.newArray(heap.size());
while(!heap.isEmpty()) {
nids.add(heap.poll().getDBID());
}
neighbors.put(id, nids);
}
// normalize the adjacent Matrix
// Sum based normalization - don't use E.normalizeColumns()
// Which normalized to Euclidean length 1.0!
// Also do the -c multiplication in this process.
for(int i = 0; i < E.getColumnDimensionality(); i++) {
double sum = 0.0;
for(int j = 0; j < E.getRowDimensionality(); j++) {
sum += E.get(j, i);
}
if(sum == 0) {
sum = 1.0;
}
for(int j = 0; j < E.getRowDimensionality(); j++) {
E.set(j, i, -c * E.get(j, i) / sum);
}
}
// Add identity matrix. The diagonal should still be 0s, so this is trivial.
assert (E.getRowDimensionality() == E.getColumnDimensionality());
for(int col = 0; col < E.getColumnDimensionality(); col++) {
assert (E.get(col, col) == 0.0);
E.set(col, col, 1.0);
}
E = E.inverse().timesEquals(1 - c);
// Split the matrix into columns
for(int i = 0; i < ids.size(); i++) {
DBID id = ids.get(i);
// Note: matrix times ith unit vector = ith column
Vector sim = E.getColumnVector(i);
similarityVectors.put(id, sim);
}
E = null;
// compute the relevance scores between specified Object and its neighbors
DoubleMinMax minmax = new DoubleMinMax();
WritableDataStore<Double> scores = DataStoreUtil.makeStorage(spatial.getDBIDs(), DataStoreFactory.HINT_STATIC, Double.class);
for(int i = 0; i < ids.size(); i++) {
DBID id = ids.get(i);
double gmean = 1.0;
int cnt = 0;
for(DBID n : neighbors.get(id)) {
if(id.equals(n)) {
continue;
}
double sim = MathUtil.cosineSimilarity(similarityVectors.get(id), similarityVectors.get(n));
gmean *= sim;
cnt++;