Mercurial > hg > jslab
diff src/samer/mds/NewMDS.java @ 0:bf79fb79ee13
Initial Mercurial check in.
author | samer |
---|---|
date | Tue, 17 Jan 2012 17:50:20 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/samer/mds/NewMDS.java Tue Jan 17 17:50:20 2012 +0000 @@ -0,0 +1,93 @@ +package samer.mds; + +import samer.core.*; +import samer.core.types.*; +import samer.maths.*; +import samer.tools.*; + +/** + This is a version that does not use a separete metric and + stress function: the stress function is defined directly in terms + of the displacement vectors between objects. The distances + are now generalised link targets. + */ +public class NewMDS extends MDSBase +{ + Stress stress; // stress function + + public interface Stress { + /** accumulate stress due to a link given end points, return gradient + in g, return true if gradient is usable, false of gradient is bad (eg singularity) */ + boolean add( double target, double [] x, double [] y, double [] g); + + /** return normalised stress and reset for next time */ + double done(); + + /** return last value returned by done() */ + double get(); + } + + public static class Laplacian implements Stress { + double S=0, a=0; + int n=0, E; + + public Laplacian(int E) { this.E=E; } + + /** add stress due to link from x to y. Force in link is returned in g. + Target is assumed to be a length measured according to a 1-norm. + */ + public boolean add( double target, double [] x, double [] y, double [] g) { + double b=0; + for (int i=0; i<E; i++) { + b+=Math.abs(x[i]-y[i]); + g[i]=sgn(x[i]-y[i]); + } + b += sqr(b/target-1); n++; + Mathx.mul(g,(b-target)/(target*target)); + return true; + } + + /** finish accumulating stress terms: reset accumulators for next + iteration and return normalised stress (ie per link) + */ + public double done() { S=a/n; a=0; n=0; return S; } + + /** return last stress value */ + public double get() { return S; } + private final static double sqr(double t) {return t*t;} + private final static double sgn(double t) { + if (t<0) return -1; else if (t>0) return +1; else return 0; + } + } + + public NewMDS(Matrix p) { + super(p); + Shell.push(node); + stress=new Laplacian(E); + Shell.pop(); + } + + public void run() + { + double [][] _P=P.getArray(); + double d, dS; + int i, j, k; + + // accumulate all forces on a per object basis + + for (k=0; k<N; k++) Mathx.zero(F[k]); // zero out object forces + for (k=0; k<M; k++) { // for each link + i=l1[k]; j=l2[k]; // object indices + if (stress.add(D[k],_P[j],_P[i],f)) { + Mathx.add(E,F[i],f); + Mathx.sub(E,F[j],f); + } + } + S.set(stress.done()); + + // now move objects at the ends of each link, + // but only the first E dimensions + for (k=0; k<N; k++) Mathx.muladd(E,_P[k],F[k],rate.value); + P.changed(); + } +}