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 an alternative version of MDS that uses less memory.
|
samer@0
|
10 Rather than keep a record of the force in each link, it accumulates
|
samer@0
|
11 the link forces on a per-object basis.
|
samer@0
|
12 */
|
samer@0
|
13 public class MDS extends MDSBase
|
samer@0
|
14 {
|
samer@0
|
15 Metric metric; // metric function
|
samer@0
|
16 Stress stress; // stress function
|
samer@0
|
17
|
samer@0
|
18 public interface Metric {
|
samer@0
|
19 /** return distance between x and y, put y-x in r */
|
samer@0
|
20 double d(double [] x, double [] y, double [] r);
|
samer@0
|
21 }
|
samer@0
|
22
|
samer@0
|
23 public interface Stress {
|
samer@0
|
24 /** accumulate stress due to a link and return dStress/dcurrent */
|
samer@0
|
25 double add( double target, double current);
|
samer@0
|
26
|
samer@0
|
27 /** return normalised stress and reset for next time */
|
samer@0
|
28 double done();
|
samer@0
|
29
|
samer@0
|
30 /** return last value returned by done() */
|
samer@0
|
31 double get();
|
samer@0
|
32 }
|
samer@0
|
33
|
samer@0
|
34 public static class SamerStress implements Stress {
|
samer@0
|
35 double S=0, a=0;
|
samer@0
|
36 int n=0;
|
samer@0
|
37
|
samer@0
|
38 public double add( double target, double current) {
|
samer@0
|
39 a += sqr(current/target-1); n++;
|
samer@0
|
40 return (current-target)/(target*target);
|
samer@0
|
41 }
|
samer@0
|
42 public double done() { S=a/n; a=0; n=0; return S; }
|
samer@0
|
43 public double get() { return S; }
|
samer@0
|
44 private final static double sqr(double t) {return t*t;}
|
samer@0
|
45 }
|
samer@0
|
46
|
samer@0
|
47 public MDS(Matrix p)
|
samer@0
|
48 {
|
samer@0
|
49 super(p);
|
samer@0
|
50
|
samer@0
|
51 Shell.push(node);
|
samer@0
|
52 metric=new Euclidean();
|
samer@0
|
53 stress=new SamerStress();
|
samer@0
|
54 Shell.pop();
|
samer@0
|
55 }
|
samer@0
|
56
|
samer@0
|
57 public void setMetric(Metric m) { metric=m; }
|
samer@0
|
58
|
samer@0
|
59 public void run()
|
samer@0
|
60 {
|
samer@0
|
61 double [][] _P=P.getArray();
|
samer@0
|
62 double d, dS;
|
samer@0
|
63 int i, j, k;
|
samer@0
|
64
|
samer@0
|
65 // accumulate all forces on a per object basis
|
samer@0
|
66
|
samer@0
|
67 for (k=0; k<N; k++) Mathx.zero(F[k]); // zero out object forces
|
samer@0
|
68 for (k=0; k<M; k++) { // for each link
|
samer@0
|
69 i=l1[k]; j=l2[k]; // object indices
|
samer@0
|
70 d=metric.d(_P[i],_P[j],f); // current distance, vector from i to j in f
|
samer@0
|
71 dS=stress.add(D[k],d);
|
samer@0
|
72
|
samer@0
|
73 if (d>0) { // ignore if current distance is zero
|
samer@0
|
74 // replace f with dS/dd * grad d
|
samer@0
|
75 Mathx.mul(f,dS/d);
|
samer@0
|
76
|
samer@0
|
77 // f contains 'force' on j from i
|
samer@0
|
78 // accumulate this force for both objects (only E dimensions used)
|
samer@0
|
79 Mathx.add(E,F[i],f);
|
samer@0
|
80 Mathx.sub(E,F[j],f);
|
samer@0
|
81 }
|
samer@0
|
82 }
|
samer@0
|
83 S.set(stress.done());
|
samer@0
|
84
|
samer@0
|
85 // now move objects at the ends of each link,
|
samer@0
|
86 // but only the first E dimensions
|
samer@0
|
87 for (k=0; k<N; k++) Mathx.muladd(E,_P[k],F[k],rate.value);
|
samer@0
|
88 P.changed();
|
samer@0
|
89 }
|
samer@0
|
90 }
|