view src/samer/mds/NewMDS.java @ 8:5e3cbbf173aa tip

Reorganise some more
author samer
date Fri, 05 Apr 2019 22:41:58 +0100
parents bf79fb79ee13
children
line wrap: on
line source
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();
	}
}