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();
+	}
+}