# Chase-san/SelfOrganizingMap

Robo Home | Chase-san | Changes | Preferences | AllPages

Difference (from prior major revision) (no other diffs)

Added: 3a4,5
 import java.util.*;

Changed: 10c12
 protected int timeIndex;
 protected int timeIndex = 1;

Added: 11a14,16
 private Queue updateQueue = new LinkedList(); private Update nextUpdate = null;

Changed: 17c22
 * @param weights - the nubmer of weights found in a node
 * @param weights - the number of weights found in a node

Added: 29a35,37
 // if(lattice[i] > maxLatticeDim?) { // maxLatticeDim? = lattice[i]; // } //end if

Removed: 52d59
 //Initializes? each node randomly, not very well done

Removed: 55,61d61
 //I have found that in a 2D map with equal dimensions //that if you set each weight outward from the center //at a distance of about a quarter, and then guassian //it from there with a .5 = dimension/4, that it works //alot better, but my code is far to complex and messy //to include here

Changed: 67c67
 for(int i=0; i
 for(int i=0; i

Added: 71a72,95
 public int size() { return nodes.length; } public void addUpdate(double[] input, int index) { updateQueue.offer(new Update(input,index)); } public void distributeUpdate(int num) { if((nextUpdate == null || nextUpdate.startNode > size()) && !updateQueue.isEmpty()) { nextUpdate = updateQueue.poll(); bmu = getBMU(nextUpdate.weights); timeIndex++; } if(nextUpdate == null) return; for(int i=nextUpdate.startNode; i

Changed: 77c101
 for(int i=0; i
 for(int i=0; i

Added: 89a114,126
 private class Update { public double[] weights; public int index; public int startNode; public Update(double w[], int i) { weights = w; index = i; startNode = 0; } }

Changed: 107,112c144
 //Make? this smarter, it should degrade over time, and it determines //The? size of the area to update, it should be based on the physical //size of the map, not the number of nodes (easiest is the smallest dimension) //I find its best if it slowly decreases in size over about 100 to 1000 ticks/updates double variance = 10/map.timeIndex;
 double variance = Math.min(2,Math.log(.2*map.timeIndex+1)+.25);

Added: 113a146,148
 //double limiter = Math.max(Math.exp(-(map.timeIndex/1000)),.75); if(neighborhood < 0.001) return;

Removed: 115,122d149
 //This? makes the whole thing ALOT faster. Remove for precision or if //you wanna test how you bot handles turn skipping. if(neighborhood < 0.0002) return; //Much? more can be done here, this should also be based on time //and it is, however if this is the bmu, then it will get changed //to the input, an undesirable thing later on. I never did this in //my prototype gun, I could of achieved greater precision here

Removed: 127,130d153
 //This? is just the index updating, very important to multiply in the neighborhood //otherwise it gets very messy later on, not to much you can do here unlike other areas //.7 is purely a magic number I came up with, I find binIndexes / 30 works well too

Removed: 135,137d157
 // statBin[i] = KTools.rollingAvg(bin[i], neighborhood*input, // Math.min(update_num, 5), 100);

Changed: 169c189,191
 Yah, I realize I could do better for an example, but I really wanna see what everyone else can come up with for this, its a very basic SOM system, I have myself introduced my own distributed update and so on, this is just the data control. If you like I can add things into this, but I am not an expert programmer, and my methods are anything but pretty. --Chase-san
 Yah, I realize I could do better for an example, but I really wanna see what everyone else can come up with for this, its a very basic SOM system, I have myself introduced my own distributed update and so on, this is just the data control. If you like I can add things into this, but I am not an expert programmer, and my methods are anything but pretty. --Chase-san Its still not running 100% when I plug it into my old prototype gun, but mostly cause I think it uses much more well formed code. ;) --Chase-san

```package chase.s2.net;

import java.util.*;

public class SelfOrganizingMap {
protected SelfOrganizedNode[] nodes;
protected SelfOrganizedNode bmu;
protected int[] lattice;
protected int statBinIndexes;
protected int weights;
protected int timeIndex = 1;

private Queue<Update> updateQueue = new LinkedList<Update>();
private Update nextUpdate = null;

/**
* Creates a self organizing map with a lattice size, stat indexes and
* number of node weights as stated.
* @param lattice - An array of integers, designating a shape of the lattice
* @param statIndexes - number of indexes in output array
* @param weights - the number of weights found in a node
*/
public SelfOrganizingMap(int[] lattice, int statIndexes, int weights) {
if(lattice.length < 1)
throw new RuntimeException("Lattice requires atleast 1 dimension.");

statBinIndexes = statIndexes;
this.lattice = lattice;
this.weights = weights;

int latticeSize = 1;
for(int i=0; i<lattice.length; i++) {
latticeSize *= lattice[i];
//			if(lattice[i] > maxLatticeDim) {
//				maxLatticeDim = lattice[i];
//			} //end if
} //end for

nodes = new SelfOrganizedNode[latticeSize];
int[] vector = new int[lattice.length];

for(int i=0; i<latticeSize; i++) {
nodes[i] = new SelfOrganizedNode(vector, this);

initialize(nodes[i], vector);

vector++;
for(int j=1; j<lattice.length; j++) {
if(vector[j-1] >= lattice[j-1]) {
vector[j-1] = 0;
vector[j]++;
} //end if
} //end for
} //end for
}

//Notice: In desperate need of a better initialization!
private void initialize(SelfOrganizedNode n, int[] position) {
for(int i=0; i<weights; i++)
n.weights[i] = Math.random();
}

public void updateMap(double[] input, int index) {
timeIndex++;
bmu = getBMU(input);
for(int i=0; i<size();i++) {
nodes[i].update(input, index);
}
}

public int size() {
return nodes.length;
}

public void addUpdate(double[] input, int index) {
updateQueue.offer(new Update(input,index));
}

public void distributeUpdate(int num) {
if((nextUpdate == null || nextUpdate.startNode > size())
&& !updateQueue.isEmpty()) {
nextUpdate = updateQueue.poll();
bmu = getBMU(nextUpdate.weights);
timeIndex++;
}
if(nextUpdate == null) return;

for(int i=nextUpdate.startNode; i<size()
&& i < (nextUpdate.startNode + num); i++) {
nodes[i].update(nextUpdate.weights, nextUpdate.index);
nextUpdate.startNode++;
}
}

public SelfOrganizedNode getBMU(double[] input) {
int bmu = 0;
double smallestDifference = Double.POSITIVE_INFINITY;

//there is no faster way as the data in the nodes changes constantly
for(int i=0; i<size(); i++) {
double difference = nodes[i].difference(input);

//small shortcut, as we need every ounce of speed
if(difference < 0.002) return nodes[i];
if(difference < smallestDifference) {
bmu = i;
smallestDifference = difference;
}
}

return nodes[bmu];
}

private class Update {
public double[] weights;
public int index;
public int startNode;

public Update(double w[], int i) {
weights = w;
index = i;
startNode = 0;
}
}
}

public class SelfOrganizedNode {
protected SelfOrganizingMap map;
protected int position[];
protected double weights[];
public float statBin[];

protected SelfOrganizedNode(int[] latticePosition, SelfOrganizingMap parent) {
position = latticePosition.clone();
map = parent;
statBin = new float[map.statBinIndexes];
weights = new double[map.weights];
}

public void update(double[] input, int index) {
double distance = distance(map.bmu);
double variance = Math.min(2,Math.log(.2*map.timeIndex+1)+.25);
double neighborhood = Math.exp(-(variance*variance*distance*distance)/2.0);
//double limiter = Math.max(Math.exp(-(map.timeIndex/1000)),.75);

if(neighborhood < 0.001) return;

for(int i=0; i < map.weights; i++) {
weights[i] += neighborhood*(input[i] - weights[i]);
}

for(int i=0; i<map.statBinIndexes; i++) {
int diff = Math.abs(index - i);
float stat = (float)Math.exp(-(.7*.7*diff*diff)/2.0);
statBin[i] += neighborhood*stat;
}
}

protected float distance(SelfOrganizedNode n) {
return distance(position, n.position);
}

protected double difference(double[] input) {
return distance(weights, input);
}

public static final float distance(int[] p, int[] q) {
float k, d = 0;
for(int i=0; i<p.length; i++) {
d += (k=((float)p[i]-(float)q[i]))*k;
}
return d;
}

public static final double distance(double[] p, double[] q) {
if(p == null || q == null) return Double.POSITIVE_INFINITY;
double k, d = 0;
for(int i=0; i<p.length; i++) {
d += (k=(p[i]-q[i]))*k;
}
return d;
}
}
```

## Comments

Yah, I realize I could do better for an example, but I really wanna see what everyone else can come up with for this, its a very basic SOM system, I have myself introduced my own distributed update and so on, this is just the data control. If you like I can add things into this, but I am not an expert programmer, and my methods are anything but pretty. --Chase-san

Its still not running 100% when I plug it into my old prototype gun, but mostly cause I think it uses much more well formed code. ;) --Chase-san

Robo Home | Chase-san | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited January 11, 2008 10:32 EST by Chase-san (diff)
Search: