latticeRadius = Math.max(latticeWidth, latticeHeight) / 2;
timeConstant = numIterations / Math.log(latticeRadius);
int iteration = 0;
double nbhRadius;
SOMNeuron bmu = null, temp = null;
SOMLayer curInput = null;
double learningRate = initialLearningRate;
while (iteration < numIterations && running) {
LOGGER.debug("Training, iteration: " + iteration);
nbhRadius = getNeighborhoodRadius(iteration);
// For each of the input vectors, look for the best matching
// unit, then adjust the weights for the BMU's neighborhood
for (int i = 0; i < inputs.size(); i++) {
curInput = (SOMLayer) inputs.elementAt(i);
bmu = lattice.getBMU(curInput);
// We have the BMU for this input now, so adjust everything in
// it's neighborhood
// Optimization: Only go through the X/Y values that
// fall within
// the radius
xstart = (int) (bmu.getX() - nbhRadius - 1);
ystart = (int) (bmu.getY() - nbhRadius - 1);
xend = (int) (xstart + (nbhRadius * 2) + 1);
yend = (int) (ystart + (nbhRadius * 2) + 1);
if (xend > latticeWidth) {
xend = latticeWidth;
}
if (xstart < 0) {
xstart = 0;
}
if (yend > latticeHeight) {
yend = latticeHeight;
}
if (ystart < 0) {
ystart = 0;
}
for (int x = xstart; x < xend; x++) {
for (int y = ystart; y < yend; y++) {
temp = lattice.getNeuron(x, y);
dist = bmu.distanceTo(temp);
if (dist <= (nbhRadius * nbhRadius)) {
dFalloff = getDistanceFalloff(dist, nbhRadius);
temp.updateWeights(curInput,
learningRate, dFalloff);
}