package ch.akuhn.mds; import java.io.PrintStream; import java.util.EventListener; import ch.akuhn.isomap.Isomap; import ch.akuhn.matrix.DenseMatrix; import ch.akuhn.matrix.Function; import ch.akuhn.matrix.SymmetricMatrix; import ch.akuhn.org.ggobi.plugins.ggvis.Mds; import ch.akuhn.org.ggobi.plugins.ggvis.Points; /** Multidimensional scaling, based on GGobi/GGvis. * * @author Adrian Kuhn, 2009 * */ public class MultidimensionalScaling { private Points fInitialConfiguration; private DenseMatrix fdistances; private int fiterations = 100; private MultidimensionalScalingListener fListener; private PrintStream fOut; private double fThreshold = 1e-6; public MultidimensionalScaling initialConfiguration(double[] x, double[] y) { fInitialConfiguration = new Points(x, y); return this; } public MultidimensionalScaling dissimilarities(double[][] matrix) { fdistances = SymmetricMatrix.fromSquare(matrix); return this; } public MultidimensionalScaling listener(MultidimensionalScalingListener listener) { this.fListener = listener; return this; } public MultidimensionalScaling iterations(int iterations) { this.fiterations = iterations; return this; } public double[][] run() { if (fdistances.rowCount() == 0) return new double[0][2]; Mds mds = new Mds(fdistances, fInitialConfiguration, Function.IDENTITY, Function.IDENTITY, Function.IDENTITY); int len = fdistances.rowCount(); fdistances = null; fInitialConfiguration = null; loop: while (fiterations > 0) { if (fListener != null) fListener.update(mds); long t = System.nanoTime(); double prev = 1.0; for (int n = 0; n < 5; n++) { mds.mds_once(true); mds.mds_once(true); double stress = mds.stress; if (prev - stress < fThreshold) break loop; prev = stress; } if (fOut != null) fOut.printf("%d, %d (stress=%f)\n", (int) (1e9 * 10 / (System.nanoTime() - t)), (int) (1e9 * 10 * len / (System.nanoTime() - t)), prev); fiterations -= 10; } if (fListener != null) fListener.update(mds); return mds.points(); } public MultidimensionalScaling similarities(double[][] matrix) { DenseMatrix d = SymmetricMatrix.fromSquare(matrix); d.apply(Function.COSINE_TO_DISSIMILARITY); fdistances = d; return this; } public MultidimensionalScaling verbose() { fOut = System.out; return this; } public MultidimensionalScaling threshold(double t) { fThreshold = t; return this; } public interface MultidimensionalScalingListener extends EventListener { public void update(Mds mds); } @Deprecated public void applyIsomapWithKayNearestNeighbors(int k) { throw new Error("should use new " + Isomap.class); } }