Mercurial > hg > jslab
diff src/samer/mds/MDS.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/MDS.java Tue Jan 17 17:50:20 2012 +0000 @@ -0,0 +1,90 @@ +package samer.mds; + +import samer.core.*; +import samer.core.types.*; +import samer.maths.*; +import samer.tools.*; + +/** + This is an alternative version of MDS that uses less memory. + Rather than keep a record of the force in each link, it accumulates + the link forces on a per-object basis. + */ +public class MDS extends MDSBase +{ + Metric metric; // metric function + Stress stress; // stress function + + public interface Metric { + /** return distance between x and y, put y-x in r */ + double d(double [] x, double [] y, double [] r); + } + + public interface Stress { + /** accumulate stress due to a link and return dStress/dcurrent */ + double add( double target, double current); + + /** return normalised stress and reset for next time */ + double done(); + + /** return last value returned by done() */ + double get(); + } + + public static class SamerStress implements Stress { + double S=0, a=0; + int n=0; + + public double add( double target, double current) { + a += sqr(current/target-1); n++; + return (current-target)/(target*target); + } + public double done() { S=a/n; a=0; n=0; return S; } + public double get() { return S; } + private final static double sqr(double t) {return t*t;} + } + + public MDS(Matrix p) + { + super(p); + + Shell.push(node); + metric=new Euclidean(); + stress=new SamerStress(); + Shell.pop(); + } + + public void setMetric(Metric m) { metric=m; } + + 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 + d=metric.d(_P[i],_P[j],f); // current distance, vector from i to j in f + dS=stress.add(D[k],d); + + if (d>0) { // ignore if current distance is zero + // replace f with dS/dd * grad d + Mathx.mul(f,dS/d); + + // f contains 'force' on j from i + // accumulate this force for both objects (only E dimensions used) + 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(); + } +}