/*
* Apache License
* Version 2.0, January 2004
* http://www.apache.org/licenses/
*
* Copyright 2013 Aurelian Tutuianu
* Copyright 2014 Aurelian Tutuianu
* Copyright 2015 Aurelian Tutuianu
* Copyright 2016 Aurelian Tutuianu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package rapaio.ml.analysis;
import rapaio.core.distributions.Uniform;
import rapaio.data.Frame;
import rapaio.data.Numeric;
import rapaio.data.SolidFrame;
import rapaio.math.linear.RM;
import rapaio.math.linear.dense.SolidRM;
import rapaio.ml.common.distance.Distance;
import rapaio.util.Tag;
import java.util.function.BiConsumer;
/**
* Iterative re-weighting map
* <p>
* Created by <a href="mailto:padreati@yahoo.com">Aurelian Tutuianu</a> on 10/6/15.
*/
public class IRM {
private Tag<Distance> distance = Distance.EUCLIDEAN;
private double tol = 1e-20;
private int maxRuns = 100;
private double s = 2;
private int len;
private Numeric x;
private Numeric y;
private RM d;
private BiConsumer<IRM, Integer> runningHook = null;
public IRM withMaxRuns(int maxRuns) {
this.maxRuns = maxRuns;
return this;
}
public IRM withRunningHook(BiConsumer<IRM, Integer> c) {
this.runningHook = c;
return this;
}
public void learn(Frame df) {
len = df.rowCount();
Uniform uniform = new Uniform(0, 1);
x = Numeric.from(len, uniform::sampleNext).withName("x");
y = Numeric.from(len, uniform::sampleNext).withName("y");
d = SolidRM.fill(len, len, 0);
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
double dist = distance.get().distance(df, i, df, j, df.varNames());
d.set(i, j, dist);
d.set(j, i, dist);
}
}
for (int r = 0; r < maxRuns; r++) {
for (int i = 0; i < len; i++) {
double xStep = 0;
double yStep = 0;
for (int j = 0; j < len; j++) {
if (i == j)
continue;
double xx = x.value(j) - x.value(i);
double yy = y.value(j) - y.value(i);
double norm = Math.sqrt(xx * xx + yy * yy);
xStep += xx * Math.pow((norm - d.get(i, j)) / norm, 2) / s;
yStep += yy * Math.pow((norm - d.get(i, j)) / norm, 2) / s;
x.setValue(i, x.value(i) + xStep);
y.setValue(i, y.value(i) + yStep);
}
}
if (runningHook != null) {
runningHook.accept(this, r);
}
}
}
public Frame getMap() {
return SolidFrame.byVars(x, y);
}
}