annotate 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
rev   line source
samer@0 1 package samer.mds;
samer@0 2
samer@0 3 import samer.core.*;
samer@0 4 import samer.core.types.*;
samer@0 5 import samer.maths.*;
samer@0 6 import samer.tools.*;
samer@0 7
samer@0 8 /**
samer@0 9 This is a version that does not use a separete metric and
samer@0 10 stress function: the stress function is defined directly in terms
samer@0 11 of the displacement vectors between objects. The distances
samer@0 12 are now generalised link targets.
samer@0 13 */
samer@0 14 public class NewMDS extends MDSBase
samer@0 15 {
samer@0 16 Stress stress; // stress function
samer@0 17
samer@0 18 public interface Stress {
samer@0 19 /** accumulate stress due to a link given end points, return gradient
samer@0 20 in g, return true if gradient is usable, false of gradient is bad (eg singularity) */
samer@0 21 boolean add( double target, double [] x, double [] y, double [] g);
samer@0 22
samer@0 23 /** return normalised stress and reset for next time */
samer@0 24 double done();
samer@0 25
samer@0 26 /** return last value returned by done() */
samer@0 27 double get();
samer@0 28 }
samer@0 29
samer@0 30 public static class Laplacian implements Stress {
samer@0 31 double S=0, a=0;
samer@0 32 int n=0, E;
samer@0 33
samer@0 34 public Laplacian(int E) { this.E=E; }
samer@0 35
samer@0 36 /** add stress due to link from x to y. Force in link is returned in g.
samer@0 37 Target is assumed to be a length measured according to a 1-norm.
samer@0 38 */
samer@0 39 public boolean add( double target, double [] x, double [] y, double [] g) {
samer@0 40 double b=0;
samer@0 41 for (int i=0; i<E; i++) {
samer@0 42 b+=Math.abs(x[i]-y[i]);
samer@0 43 g[i]=sgn(x[i]-y[i]);
samer@0 44 }
samer@0 45 b += sqr(b/target-1); n++;
samer@0 46 Mathx.mul(g,(b-target)/(target*target));
samer@0 47 return true;
samer@0 48 }
samer@0 49
samer@0 50 /** finish accumulating stress terms: reset accumulators for next
samer@0 51 iteration and return normalised stress (ie per link)
samer@0 52 */
samer@0 53 public double done() { S=a/n; a=0; n=0; return S; }
samer@0 54
samer@0 55 /** return last stress value */
samer@0 56 public double get() { return S; }
samer@0 57 private final static double sqr(double t) {return t*t;}
samer@0 58 private final static double sgn(double t) {
samer@0 59 if (t<0) return -1; else if (t>0) return +1; else return 0;
samer@0 60 }
samer@0 61 }
samer@0 62
samer@0 63 public NewMDS(Matrix p) {
samer@0 64 super(p);
samer@0 65 Shell.push(node);
samer@0 66 stress=new Laplacian(E);
samer@0 67 Shell.pop();
samer@0 68 }
samer@0 69
samer@0 70 public void run()
samer@0 71 {
samer@0 72 double [][] _P=P.getArray();
samer@0 73 double d, dS;
samer@0 74 int i, j, k;
samer@0 75
samer@0 76 // accumulate all forces on a per object basis
samer@0 77
samer@0 78 for (k=0; k<N; k++) Mathx.zero(F[k]); // zero out object forces
samer@0 79 for (k=0; k<M; k++) { // for each link
samer@0 80 i=l1[k]; j=l2[k]; // object indices
samer@0 81 if (stress.add(D[k],_P[j],_P[i],f)) {
samer@0 82 Mathx.add(E,F[i],f);
samer@0 83 Mathx.sub(E,F[j],f);
samer@0 84 }
samer@0 85 }
samer@0 86 S.set(stress.done());
samer@0 87
samer@0 88 // now move objects at the ends of each link,
samer@0 89 // but only the first E dimensions
samer@0 90 for (k=0; k<N; k++) Mathx.muladd(E,_P[k],F[k],rate.value);
samer@0 91 P.changed();
samer@0 92 }
samer@0 93 }