/* Copyright (C) 2006 Leonardo Bispo de Oliveira and
* Daniele Sunaga de Oliveira
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package br.com.ibmp.som.matrix;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import br.com.ibmp.som.distance.DistanceMethodInterface;
import br.com.ibmp.som.exception.SOMException;
import br.com.ibmp.som.matrix.vo.SOMElementVO;
import br.com.ibmp.som.matrix.vo.WeightElementVO;
import br.com.ibmp.som.neighbors.NeighborsMethodInterface;
/**
* Class that contains the Weight elements matrix. This class
* this class will do the learning process and retrieve the mounted
* groups of some sample entry.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira
* @version 1.0
*
*/
public class WeightMatrix {
/** Matrix width. */
private int width;
/** Matrix height. */
private int height;
/** Sample vector that contains the learning elements. */
private SampleVectorInterface sampleVector;
/** Scale neighbors and learning method. */
private NeighborsMethodInterface neighborsMethod;
/** Distance calcule method. */
private DistanceMethodInterface distanceMethod;
/** The weight matrix. This matrix is inatingible by the user. */
private WeightElementVO[][] matrix;
/** Random instance. */
private Random randomize;
/**
* Contructor.
*
* @param width - Matrix width.
* @param height - Matrix height.
* @param sampleVector - Sample vector that contains the learning elements.
* @param neighborsMethod - Scale neighbors and learning method.
* @param distanceMethod - Distance calcule method.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira.
*
* @throws SOMException
*
*/
public WeightMatrix(int width, int height, SampleVectorInterface sampleVector,
NeighborsMethodInterface neighborsMethod, DistanceMethodInterface distanceMethod)
throws SOMException {
int i, j;
if (neighborsMethod == null)
throw new SOMException("Not valid neighbors method");
this.width = width;
this.height = height;
randomize = new Random();
this.sampleVector = sampleVector;
this.neighborsMethod = neighborsMethod;
this.distanceMethod = distanceMethod;
matrix = new WeightElementVO[width][height];
for (i = 0; i < width; i++)
for (j = 0; j < height; j++)
matrix[i][j] = new WeightElementVO(i, j, sampleVector.randomizeWeight());
}
/**
* Assessor to retrieve the matrix width.
*
* @return The matrix width.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira.
*
*/
public int getWidth() {
return width;
}
/**
* Assessor to retrieve the matrix height.
*
* @return The matrix height.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira.
*
*/
public int getHeight() {
return height;
}
/**
* Assessor for returning the best weight from some sample. If more then
* one weight match then we return a random weight.
*
* @param matrix - Weight matrix for returning the best weight.
* @param sample - Sample element to be match.
*
* @return Best matching weight.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira.
*
* @throws SOMException
*
*/
protected WeightElementVO getBestMatchingWeight(WeightElementVO[][] matrix,
SOMElementVO sample) throws SOMException {
int i, j;
double bestDistance, currDistance;
List<WeightElementVO> matchList;
bestDistance = Double.MAX_VALUE;
matchList = null;
for (i = 0; i < width; i++) {
for (j = 0; j < height; j++) {
currDistance = distanceMethod.calculateDistance(sample,
matrix[i][j].getWeight());
if (currDistance == bestDistance)
matchList.add(matrix[i][j]);
else if (currDistance < bestDistance) {
bestDistance = currDistance;
matchList = new ArrayList<WeightElementVO>();
matchList.add(matrix[i][j]);
}
}
}
return matchList.get(randomize.nextInt(matchList.size()));
}
/**
* Assessor for returning the best weight from some sample. If more then
* one weight match then we return a random weight.
*
* @param matrix - Weight matrix for returning the best weight.
* @param sample - Sample element to be match.
*
* @return Best matching weight.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira.
*
* @throws SOMException
*
*/
protected WeightElementVO getBestUMatchingWeight(WeightElementVO[][] matrix,
SOMElementVO sample) throws SOMException {
int i, j;
double bestDistance, currDistance;
List<WeightElementVO> matchList;
bestDistance = Double.MAX_VALUE;
matchList = null;
for (i = 0; i < (width*2); i += 2) {
for (j = 0; j < (height*2); j += 2) {
currDistance = distanceMethod.calculateDistance(sample,
matrix[i][j].getWeight());
if (currDistance == bestDistance)
matchList.add(matrix[i][j]);
else if (currDistance < bestDistance) {
bestDistance = currDistance;
matchList = new ArrayList<WeightElementVO>();
matchList.add(matrix[i][j]);
}
}
}
return matchList.get(randomize.nextInt(matchList.size()));
}
/**
* Class interface to execute a step learn.
*
* @param t - Time to be used in learning process.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira.
*
* @throws SOMException
*
*/
public void executeStepLearn(double t) throws SOMException {
SOMElementVO sample;
WeightElementVO bestWeight;
sample = sampleVector.randomizeSample();
bestWeight = getBestMatchingWeight(matrix, sample);
neighborsMethod.scaleNeighbors(width, height, matrix,
bestWeight, t, distanceMethod);
}
/**
* Set the matrix distance between components.
*
* @param groups - The U-Matrix.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira.
*
*/
protected void setUMatrixDistances(WeightElementVO[][] groups) {
int i, j;
/////////////////////////////////////////////////////////////////
//TODO - Algorithm to set the distance between elements !!!
// I Have problems to calculate the distance, then I will
// need some DANIELES help. Develop this with her.
/////////////////////////////////////////////////////////////////
for (i = 0; i < groups.length; i++) {
for (j = 0; j < groups[i].length; j++) {
if (j%2 == 0)
groups[i][j].setPercentageDistance(0);
else
groups[i][j].setPercentageDistance(100);
}
}
}
/**
* Assessor to retrieve the U-Matrix generated by Self organizing method.
*
* @param sampleVector - Samples to be put on weight matrix.
*
* @return The U-Matrix matrix.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira
*
* @throws SOMException
*
*/
public WeightElementVO[][] mountUMatrix(SampleVectorInterface sampleVector)
throws SOMException {
int i, j, tmpI, tmpJ;
SOMElementVO element;
WeightElementVO group;
WeightElementVO[][] groups;
groups = new WeightElementVO[width*2][height*2];
//////////////////////////////////////////////////////////////////////////////////////
//FIXME - This Alorithm should be better. I do this just for cleaning compreention.
// Maybe I'll fix it latter.
//////////////////////////////////////////////////////////////////////////////////////
for (i = 0, tmpI = 0; tmpI < (width*2); i++, tmpI += 2) {
for (j = 0, tmpJ = 0 ; tmpJ < (height*2); j++, tmpJ += 2) {
groups[tmpI][tmpJ] = new WeightElementVO(tmpI, tmpJ, matrix[i][j].getWeight());
}
}
for (i = 1; i < (width*2); i +=2 )
for (j = 0; j < (height*2); j += 2)
groups[i][j] = new WeightElementVO(i, j, null);
for (i = 0; i < (width*2); i++) {
for (j = 1; j < (height*2); j += 2)
groups[i][j] = new WeightElementVO(i, j, null);
}
setUMatrixDistances(groups);
for (i = 0; i < sampleVector.getRowSize(); i++) {
element = sampleVector.getElement(i);
group = getBestUMatchingWeight(groups, element);
group.addOnGroup(element);
}
return groups;
}
/**
* Assessor to retrieve the groups generated by Self organizing method.
*
* @param sampleVector - Samples to be put on weight matrix.
*
* @return The weight element matrix.
*
* @author Leonardo Bispo de Oliveira and Daniele Sunaga de Oliveira
*
* @throws SOMException
*
*/
public WeightElementVO[][] mountGroups(SampleVectorInterface sampleVector) throws SOMException {
int i, j;
SOMElementVO element;
WeightElementVO group;
WeightElementVO[][] groups;
groups = new WeightElementVO[width][height];
for (i = 0; i < width; i++)
for (j = 0; j < height; j++)
groups[i][j] = new WeightElementVO(i, j, matrix[i][j].getWeight());
for (i = 0; i < sampleVector.getRowSize(); i++) {
element = sampleVector.getElement(i);
group = getBestMatchingWeight(groups, element);
group.addOnGroup(element);
}
return groups;
}
}