import java.awt.*; import java.applet.*; import java.util.*; /* A colourful demonstration of SOFM Written by Simon Lucas (email sml@essex.ac.uk) Permission is granted to copy and modify this code as desired. The aim here is to capture the spirit of SOFM - I've not really paid much attention to the details e.g. choice of neighbourhood function - you can play with this by modifying the weight equation in the synapse constructor. The design of this is quite neat and simple - but I lose marks for passing a Graphics object around the SOFM implementation. This was done for reasons of efficiency - better to just update the cell colours as they change rather repaint the entire map each time. A better way to do this would be to define cell, synapse and map without any reference to a Graphics object, then subclass them with graphical versions. */ class synapse { // this class models a weighted connection to a cell double weight; static double sharpness = 2.0; // higher values give sharper cutoff cell c; public static double sigmoid(double x) { return 1.0 / (1.0 + Math.exp(-x)); } public synapse(cell c, double dist) { weight = 0.2 * sigmoid((sofm.limit - sharpness*dist)/sharpness); // weight = 0.2 / (1.0 + dist); // use simple function this.c = c; } public void update(double[] v, Graphics g) { c.update(v, map.rate*weight, g); } } class cell { // has three basic properties: a grid position (gridv) // an input space position (ipv) // and a set of neighbours (stored in a java.util.Vector) double[] gridv; double[] ipv; int d; static int neighboursEstimate = 30; // a rough estimate of number of neighbours - will grow automatically if needed to Vector neighbours; // more of a list than a vector! public cell(int d, int x, int y) { // construct a cell with a d-dimensional randomly initialised vector at // point x,y on the grid ipv = new double[d]; gridv = new double[2]; gridv[0] = (double) x; gridv[1] = (double) y; this.d = d; randCell(); neighbours = new Vector(neighboursEstimate); } public void randCell() { for (int i=0; i