de.sciss.neuralgas.ComputeGNG Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of neuralgas-core Show documentation
Show all versions of neuralgas-core Show documentation
Neural network simulator based on growing neural gas (GNG) - algorithms
// ========================================================================== ;
// ;
// Copyright 1996-1998 Hartmut S. Loos, Instit. f. Neuroinformatik, Bochum ;
// Copyright 2012-2013 Bernd Fritzke ;
// ;
// This program is free software; you can redistribute it and/or modify ;
// it under the terms of the GNU General Public License as published by ;
// the Free Software Foundation; either version 1, or (at your option) ;
// any later version. ;
// ;
// This program 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 General Public License for more details. ;
// ;
// You should have received a copy of the GNU General Public License ;
// along with this program; if not, write to the Free Software ;
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;
// ;
// ========================================================================== ;
package de.sciss.neuralgas;
import java.awt.Dimension;
import java.awt.geom.Point2D;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
/**
* A class which implements the network algorithms.
* It implements many functions/algorithms.
* The most important method is 'learn' which implements all adaptation methods
*
*/
public class ComputeGNG {
void log(String prefix, String txt) {
System.out.println(timeStamp()+" C: "+prefix+txt);
}
void log(String txt) {
log("####### ", txt);
}
final static private SimpleDateFormat format = new SimpleDateFormat("yyyy.MM.dd HH.mm.ss");
public synchronized String timeStamp() {
long lDateTime = new Date().getTime();
String str;
str = format.format(new java.util.Date())+"."+String.format("%03d",lDateTime%1000);
return str;
}
/**
* The flag for debugging.
*/
protected final boolean DEBUG = false;
/**
* The maximum number of nodes.
*/
public static final int MAX_NODES = 30000;
/**
* The maximum number of edges (3 * maximum number of nodes).
*/
protected final int MAX_EDGES = 6 * MAX_NODES;
/**
* The maximum step-size.
*/
protected final int MAX_STEP_SIZE = 500;
/**
* The size of the DiscreteMixture signal set.
*/
protected final int MIXTURE_SIZE = 500;
/**
* The maximum number of discrete numSignals.
*/
protected final int MAX_DISCRETE_SIGNALS = 20000;
/**
* The maximum x size of the grid array.
*/
protected final int MAX_GRID_X = 10000;
/**
* The maximum y size of the grid array.
*/
protected final int MAX_GRID_Y = 100;
/**
* The factor for the ring-thickness (distribution).
*/
protected static final float RING_FACTOR = 0.4f; // Factor < 1
/**
* The current maximum number of nodes.
*/
public int maxNodes = 100;
/**
* The current number of runs to insert a new node (GNG).
*/
public int lambdaGNG = 600;
/**
* The current number of input numSignals used for adaptation.
*/
public int numSignals = 0;
/**
* The temporal backup of a run.
*/
protected int numSignalsTmp = 0;
/**
* The x-position of the actual signal.
*/
public float SignalX = 0f;
/**
* The y-position of the actual signal.
*/
public float SignalY = 0f;
/**
* The initial width of the drawing area.
* This value can only be changed by resizing the applet-viewer.
*/
public int panelWidth = 648; // 550;
/**
* The initial height of the drawing area.
* This value can only be changed by resizing the applet-viewer.
*/
public int panelHeight = 377; // 310;
/**
* The actual number of nodes.
*/
public int nNodes = 0;
/**
* The array of the actual used nodes.
*/
public NodeGNG nodes[] = new NodeGNG[MAX_NODES];
/**
* The sorted array of indices of nodes.
* The indices of the nodes are sorted by their distance from the actual
* signal. sNodes[1] is the index of the nearest node.
*/
protected int sNodes[] = new int[MAX_NODES + 1];
/**
* The array of the nodes in the grid.
*/
public GridNodeGNG grid[][] = new GridNodeGNG[MAX_GRID_X][MAX_GRID_Y];
/**
* The array of the last computed numSignals (x-coordinate).
*/
public float lastSignalsX[] = new float[MAX_STEP_SIZE];
/**
* The array of the last computed numSignals (y-coordinate).
*/
public float lastSignalsY[] = new float[MAX_STEP_SIZE];
/**
* The array of the discrete numSignals (x-coordinate).
*/
public float discreteSignalsX[] = new float[MAX_DISCRETE_SIGNALS];
/**
* The array of the discrete numSignals (y-coordinate).
*/
public float discreteSignalsY[] = new float[MAX_DISCRETE_SIGNALS];
/**
* The array of the best distance (discrete numSignals).
*/
protected float discreteSignalsD1[] = new float[MAX_DISCRETE_SIGNALS];
/**
* The array of the second best distance (discrete numSignals).
*/
protected float discreteSignalsD2[] = new float[MAX_DISCRETE_SIGNALS];
/**
* The array of the second best distance (discrete numSignals).
*/
protected FPoint C_best[] = new FPoint[MAX_NODES];
/**
* The current number of discrete numSignals.
*/
public int numDiscreteSignals = 500;
/**
* The actual number of edges.
*/
public int nEdges = 0;
/**
* The array of the actual used edges.
*/
public EdgeGNG edges[] = new EdgeGNG[MAX_EDGES];
/**
* The flag for random init. The nodes will be placed only in the specified
* distribution or not.
*/
public boolean rndInitB = false;
private final Random _random;
public final double random() { return _random.nextDouble(); }
public final Random getRNG() { return _random; }
/**
* The flag for entering the fine-tuning phase (GG).
*/
public boolean fineTuningB = false;
/**
* stop the algorithm when max number of nodes is reached
*/
public boolean autoStopB = true;
/**
* close GG to a torus
*/
public boolean torusGGB = false;
/**
* close SOM to a torus
*/
public boolean torusSOMB = false;
/**
* The flag for inserting new nodes in GNG.
* This variable can be set by the user. If true no new nodes are
* inserted.
*/
public boolean noNewNodesGNGB = false;
/**
* The flag for inserting new nodes in GG.
* This variable can be set by the user. If true no new nodes are
* inserted.
*/
public boolean noNewNodesGGB = false;
/**
* The flag for variable movement (HCL).
* This variable can be set by the user.
*/
public boolean variableB = false;
/**
* The flag for using utility (GNG-U).
*/
public boolean GNG_U_B = false;
/**
* The flag for changed number of nodes.
*/
public boolean nNodesChangedB = true;
/**
* The flag for LBG-U method
*/
public boolean LBG_U_B = false;
/**
* The flag for end of calculation (LBG)
*/
public boolean readyLBG_B = false;
/**
* The selected distribution.
* This variable can be set by the user.
*/
public PD pd = PD.Rectangle;
/**
* The selected algorithm.
*/
public Algorithm algorithm = Algorithm.NG;
/**
* The current maximum number to delete an old edge (GNG,NGwCHL).
* This variable can be set by the user.
*/
public int maxEdgeAge = 88;
/**
* The current number of calculations done in one step.
* This variable can be set by the user. After stepSize
* calculations the result is displayed.
*/
public int stepSize = 50;
/**
* The actual x size of the grid array.
*/
public int gridWidth = 0;
/**
* The actual y size of the grid array.
*/
public int gridHeight = 0;
/**
* The direction factor for the x axis (-1 or 1) used for the
* 'Moving Rectangle' distribution
*/
protected int bounceX = -1;
/**
* The direction factor for the y axis (-1 or 1) used for the
* 'Moving Rectangle' distribution
*/
protected int bounceY = -1;
/**
* The x coordinate for the 'Jumping Rectangle' and 'R.Mouse' distribution
*/
public int jumpX = 250;
/**
* The y coordinate for the 'Jumping Rectangle' and 'R.Mouse' distribution
*/
public int jumpY = 250;
/**
* Stores the old x value of the remainder in order to detect the bounce
* (used for the 'Moving Rectangle' distribution)
*/
protected double bounceX_old = 1;
/**
* Stores the old y value of the remainder in order to detect the bounce
* (used for the 'Moving Rectangle' distribution)
*/
protected double bounceY_old = 1;
/**
* The value epsilon for the HCL algorithm.
* This variable can be set by the user.
*/
public float epsilon = 0.1f;
/**
* The value epsilon for the GNG algorithm (winner).
* This variable can be set by the user.
*/
public float epsilonGNG = 0.1f;
/**
* The value epsilon for the GNG algorithm (second).
* This variable can be set by the user.
*/
public float epsilonGNG2 = 0.001f;
/**
* The value alpha for the GNG algorithm.
* This variable can be set by the user.
*/
public float alphaGNG = 0.5f;
/**
* The value beta for the GNG algorithm.
* This variable can be set by the user.
*/
private float betaGNG = 0.0005f;
public void setBetaGNG(float value) {
betaGNG = value;
decayFactorUtility = 1.0f - betaGNG;
decayFactor = 1.0f - betaGNG;
}
public float getBetaGNG() {
return betaGNG;
}
/**
* maximum width of grid
*
*/
public int maxYGG = 0;
/**
* The utility factor for the GNG-U algorithm.
* This variable can be set by the user.
*/
public float utilityGNG = 3.0f;
/*
* The decay factor for utility.
* Will be recalculated in setBetaGNG
*/
private float decayFactorUtility = 1.0f - betaGNG;
/*
* The factor to forget old values.
* Will be recalculated in setBetaGNG
*/
private float decayFactor = 1.0f - betaGNG;
/**
* The value lambda initial for the NG,NGwCHL,GG algorithms.
* This variable can be set by the user.
*/
public float l_i = 30.0f;
/**
* The value lambda final for the NG,NGwCHL,GG algorithms.
* This variable can be set by the user.
*/
public float l_f = 0.01f;
/**
* The value epsilon(t) for the NG,NGwCHL algorithms.
*/
protected float e_t = 0.0f;
/**
* The value epsilon initial for the NG,NGwCHL,GG algorithms.
* This variable can be set by the user.
*/
public float e_i = 0.3f;
/**
* The value epsilon final for the NG,NGwCHL,GG algorithms.
* This variable can be set by the user.
*/
public float e_f = 0.05f;
/**
* The value t_max for the NG,NGwCHL,SOM algorithms.
* This variable can be set by the user.
*/
public float t_max = 40000.0f;
/**
* The value delete edge initial for the NGwCHL algorithm.
* This variable can be set by the user.
*/
public float delEdge_i = 20.0f;
/**
* The value delete edge final for the NGwCHL algorithm.
* This variable can be set by the user.
*/
public float delEdge_f = 200.0f;
/**
* The value sigma for the GG algorithm.
* This variable can be set by the user.
*/
public float sigma = 0.9f;
/**
* The value sigma_i for the SOM algorithm.
* This variable can be set by the user.
*/
public float sigma_i = 5.0f;
/**
* The value sigma_f for the SOM algorithm.
* This variable can be set by the user.
*/
public float sigma_f = 5.0f;
/**
* This value is displayed in the error graph.
*/
public float valueGraph = 0.0f;
/**
* This value contains the best error value for LBG-U up to now.
*/
public float errorBestLBG_U = Float.MAX_VALUE;
/**
* The string shown in the fine-tuning phase of the method GG.
*/
public String fineTuningS = "";
/**
* The constructor.
*/
public ComputeGNG(long seed) {
_random = new Random(seed);
}
public ComputeGNG() {
this(System.currentTimeMillis());
}
public void reset() {
numSignals = 0;
nNodes = 0;
nEdges = 0;
}
/**
* Add a node. The new node will be randomly placed within the
* given dimension or according to the current distribution.
*
* @param d The dimension of the initial drawing area
* @return The index of the new node
*/
public int addNode(Dimension d) {
if ( (nNodes == MAX_NODES) || (nNodes >= maxNodes) )
return -1;
NodeGNG n = new NodeGNG();
if (rndInitB) {
// init from Rectangle 0.8x0.8+(0.1,0.1)
n.x = (float) (10 + (d.width -20) * random()); // Math.random()
n.y = (float) (10 + (d.height-20) * random()); // Math.random()
} else {
// init from current distribution
getSignal(pd);
n.x = SignalX;
n.y = SignalY;
}
//System.out.printf("addNode() and width is %d and rndInit is %s, x=%f, y=%f\n",d.width, rndInitB,n.x,n.y);
n.nNeighbor = 0;
if (algorithm.isDiscrete())
n.hasMoved = true;
nodes[nNodes] = n;
nNodesChangedB = true;
return nNodes++;
}
/**
* Add a node. The new node will be placed at the
* given coordinates.
*
* @param x The x-coordinate of the new node
* @param y The y-coordinate of the new node
* @return The index of the new node
*/
public int addNode(int x, int y) {
if ( (nNodes == MAX_NODES) || (nNodes >= maxNodes) )
return -1;
NodeGNG n = new NodeGNG();
n.x = x;
n.y = y;
if (algorithm.isDiscrete()) // LBG
n.hasMoved = true;
nodes[nNodes] = n;
nNodesChangedB = true;
return nNodes++;
}
/**
* Add a node. The new node will be placed between the
* given nodes which must be connected. The existing edge is splitted.
* The new node gets the average of the interesting values of
* the two given nodes.
*
* @param n1 The index of a node
* @param n2 The index of a node
* @return The index of the new node
*/
protected int insertNode(int n1, int n2) {
if ( (nNodes == MAX_NODES) || (nNodes >= maxNodes) )
return -1;
if ( (n1 < 0) || (n2 < 0) )
return -1;
NodeGNG n = new NodeGNG();
float dx = (nodes[n1].x - nodes[n2].x) / 2.0f;
float dy = (nodes[n1].y - nodes[n2].y) / 2.0f;
// reduce errors of neighbor nodes of the new unit
nodes[n1].error *= (1.0f - alphaGNG);
nodes[n2].error *= (1.0f - alphaGNG);
// interpolate error from neighbors
n.error = (nodes[n1].error + nodes[n2].error)/2.0f;
// interpolate utility from neighbors
n.utility = (nodes[n1].utility + nodes[n2].utility)/2.0f;
// interpolate coordinates
n.x = nodes[n1].x - dx;
n.y = nodes[n1].y - dy;
n.isMostRecentlyInserted = true;
nodes[nNodes] = n;
deleteEdge(n1, n2);
addEdge(n1, nNodes); //n1<->new
addEdge(n2, nNodes); //n2<->new
nNodesChangedB = true;
return nNodes++;
}
/**
* Add a node into the grid. The new node will be randomly placed within the
* given dimension.
*
* @param x The x coordinate of the grid array
* @param y The y coordinate of the grid array
* @param d The dimension of the initial drawing area
* @return The index of the new node
*/
protected int addGridNode(int x, int y, Dimension d) {
if ( (x > MAX_GRID_X) || (y > MAX_GRID_Y) )
return -1;
int n = addNode(d);
nodes[n].x_grid = x;
nodes[n].y_grid = y;
grid[x][y] = new GridNodeGNG(n, nodes[n]);
return n;
}
/**
* Initialize the grid. The new nodes will be randomly placed within the
* given dimension.
*
* @param width The width of the grid array
* @param height The height of the grid array
* @param d The dimension of the initial drawing area
*/
public void initGrid(int width, int height, Dimension d) {
if ( (width > MAX_GRID_X) || (height > MAX_GRID_Y) ){
throw new IllegalStateException ( ); // hack bf
//return;
}
int i, j;
if (algorithm == Algorithm.SOM)
maxNodes = width * height;
//
// add nodes
//
for (i = 0; i < width; i++)
for (j = 0; j < height; j++)
{
addGridNode(i, j, d);
}
gridWidth = width;
gridHeight = height;
//
// add edges
//
for (i = 0; i < gridWidth; i++) {
for (j = 0; j < gridHeight; j++) {
if ( i < (gridWidth - 1) )
addEdge(grid[i][j].index, grid[i+1][j].index);
if ( j < (gridHeight - 1) )
addEdge(grid[i][j].index, grid[i][j+1].index);
}
}
}
/**
* Prepare to insert a row or column into the grid.
*
* @return The index of the last inserted node or -1
*/
protected boolean enlargeGrid() {
float tau = 0;
int x = 0;
int y = 0;
int n = -1;
float d1 = 0, d2 = 0, d3 = 0, d4 = 0, max = 0;
for (int j = 0; j < gridHeight; j++) {
for (int i = 0; i < gridWidth; i++) {
// Find maximum resource value tau
if ( grid[i][j].node.tau > tau ) {
tau = grid[i][j].node.tau;
x = i;
y = j;
}
//System.out.print(String.format("%06.03f", grid[i][j].node.tau));
//System.out.print(", ");
grid[i][j].node.tau = 0; // clear tau value
grid[i][j].node.isMostRecentlyInserted = false;
}
//System.out.println();
}
//log(String.format("maximum tau value: %f x: %d y: %d width: %d height: %d", tau,x,y,gridWidth, gridHeight));
// assertion: grid[x][y] is the node with maximum tau value
// Identify the neighbor of (x,y) with the most different reference vector
// left neighbor
if (x > 0)
d1 = (grid[x-1][y].node.x - grid[x][y].node.x) *
(grid[x-1][y].node.x - grid[x][y].node.x) +
(grid[x-1][y].node.y - grid[x][y].node.y) *
(grid[x-1][y].node.y - grid[x][y].node.y);
// upper neighbor
if (y > 0)
d2 = (grid[x][y-1].node.x - grid[x][y].node.x) *
(grid[x][y-1].node.x - grid[x][y].node.x) +
(grid[x][y-1].node.y - grid[x][y].node.y) *
(grid[x][y-1].node.y - grid[x][y].node.y);
// right neighbor
if (x < gridWidth - 1)
d3 = (grid[x+1][y].node.x - grid[x][y].node.x) *
(grid[x+1][y].node.x - grid[x][y].node.x) +
(grid[x+1][y].node.y - grid[x][y].node.y) *
(grid[x+1][y].node.y - grid[x][y].node.y);
// lower neighbor
if (y < gridHeight - 1)
d4 = (grid[x][y+1].node.x - grid[x][y].node.x) *
(grid[x][y+1].node.x - grid[x][y].node.x) +
(grid[x][y+1].node.y - grid[x][y].node.y) *
(grid[x][y+1].node.y - grid[x][y].node.y);
if ((maxYGG > 0) && (gridHeight >= maxYGG )) { //
d4=0;
d2=0;
}
max = Math.max(d1, Math.max(d2, Math.max(d3, d4)));
if (max == d1) // left
n = insertColumn(x - 1);
else if (max == d2) // upper
n = insertRow(y - 1);
else if (max == d3) // right
n = insertColumn(x);
else // lower
n = insertRow(y);
if (n == -1)
return false;
else
return true;
}
/**
* Add a row into the grid. The new row will be placed after index y.
*
* @param y The row index
* @return The index of the last inserted node or -1
*/
protected int insertRow(int y) {
if ( (gridHeight == MAX_GRID_Y) || (nNodes + gridWidth > maxNodes) )
return -1;
int n = -1;
int i, j;
// Insert nodes for the new row
for (i = 0; i < gridWidth; i++) {
n = addNode(0,0);
nodes[n].x_grid = i;
nodes[n].y_grid = gridHeight;
grid[i][gridHeight] = new GridNodeGNG(n, nodes[n]);
// Add Edges
if (i != 0)
addEdge(grid[i][gridHeight].index, grid[i-1][gridHeight].index);
addEdge(grid[i][gridHeight].index, grid[i][gridHeight-1].index);
}
// Now change the parameters (position)
for (j = gridHeight; j > y+1; j--) {
for (i = 0; i < gridWidth; i++) {
grid[i][j].node.x = grid[i][j-1].node.x;
grid[i][j].node.y = grid[i][j-1].node.y;
}
}
for (i = 0; i < gridWidth; i++) {
grid[i][y+1].node.x = (grid[i][y].node.x + grid[i][y+2].node.x)*0.5f;
grid[i][y+1].node.y = (grid[i][y].node.y + grid[i][y+2].node.y)*0.5f;
grid[i][y+1].node.tau = (grid[i][y].node.tau + grid[i][y+2].node.tau)*0.33f;
grid[i][y].node.tau *= 0.66f;
grid[i][y+2].node.tau *= 0.66f;
grid[i][y+1].node.isMostRecentlyInserted = true;
}
// Make the new row official
gridHeight++;
return n;
}
/**
* Add a column into the grid. The new column will be placed after index x.
*
* @param x The column index
* @return The index of the last inserted node or -1
*/
protected int insertColumn(int x) {
if ( (gridWidth == MAX_GRID_X) || (nNodes + gridHeight > maxNodes) )
// max size or dimension reached: no further insert!
return -1;
int n = -1;
int i, j;
// Insert nodes for the new Column (x-index: gridwidth)
for (j = 0; j < gridHeight; j++) {
n = addNode(0,0);
nodes[n].x_grid = gridWidth;
nodes[n].y_grid = j;
grid[gridWidth][j] = new GridNodeGNG(n, nodes[n]);
// Add Edges
if (j != 0)
addEdge(grid[gridWidth][j].index, grid[gridWidth][j-1].index);
addEdge(grid[gridWidth][j].index, grid[gridWidth-1][j].index);
}
// Now change the parameters (position)
// i.e. make space for new column x+1 by moving columns x+1 and following to the right
//
for (i = gridWidth; i > x+1; i--) {
for (j = 0; j < gridHeight; j++) {
grid[i][j].node.x = grid[i-1][j].node.x;
grid[i][j].node.y = grid[i-1][j].node.y;
}
}
// interpolate positions for column x+1
// relies on the fact that column x+1 still contains the old values which are also copied to x+2
for (j = 0; j < gridHeight; j++) {
//System.out.printf("interp: x=%d, j=%d\n",x,j);
grid[x+1][j].node.x = (grid[x][j].node.x + grid[x+2][j].node.x)*0.5f;
grid[x+1][j].node.y = (grid[x][j].node.y + grid[x+2][j].node.y)*0.5f;
grid[x+1][j].node.tau = (grid[x][j].node.tau +grid[x+2][j].node.tau)*1/3;
grid[x][j].node.tau *= 0.66;
grid[x+2][j].node.tau *= 0.66;
grid[x+1][j].node.isMostRecentlyInserted = true;
}
// Make the new row official
gridWidth++;
return n;
}
/**
* Delete the given node.
*
* @param n The index of a node
*/
protected void deleteNode(int n) {
NodeGNG node = nodes[n];
int num = node.numNeighbors();
int i;
for (i = 0; i < num; i++)
deleteEdge(n, node.neighbor(0));
nNodesChangedB = true;
nNodes--;
nodes[n] = nodes[nNodes];
nodes[nNodes] = null;
// Now rename all occurances of nodes[nnodes] to nodes[n]
for (i = 0 ; i < nNodes ; i++)
nodes[i].replaceNeighbor(nNodes, n);
for (i = 0 ; i < nEdges ; i++)
edges[i].replace(nNodes, n);
return;
}
/**
* Connect two nodes or reset the age of their edge.
*
* @param from The index of the first node
* @param to The index of the second node
*/
protected void addEdge(int from, int to) {
if (nNodes < 2)
return;
if (nodes[from].isNeighbor(to)) {
// Find edge(from,to) and reset age
int i = findEdge(from, to);
if (i != -1)
edges[i].age = 0;
return;
}
if (nEdges == MAX_EDGES)
return;
if ( (nodes[from].moreNeighbors()) && (nodes[to].moreNeighbors()) ) {
nodes[to].addNeighbor(from);
nodes[from].addNeighbor(to);
} else
return;
// Add new edge
EdgeGNG e = new EdgeGNG();
e.from = from;
e.to = to;
edges[nEdges] = e;
nEdges++;
}
/**
* Disconnect two nodes.
*
* @param from The index of the first node
* @param to The index of the second node
*/
protected void deleteEdge(int from, int to) {
int i = findEdge(from, to);
if (i != -1) {
nodes[edges[i].from].deleteNeighbor(edges[i].to);
nodes[edges[i].to].deleteNeighbor(edges[i].from);
nEdges--;
edges[i] = edges[nEdges];
edges[nEdges] = null;
}
return;
}
/**
* Delete an edge.
*
* @param edgeNr The index of the edge
*/
protected void deleteEdge(int edgeNr) {
nodes[edges[edgeNr].from].deleteNeighbor(edges[edgeNr].to);
nodes[edges[edgeNr].to].deleteNeighbor(edges[edgeNr].from);
nEdges--;
edges[edgeNr] = edges[nEdges];
edges[nEdges] = null;
}
/**
* Find an edge. Find the edge between the two given nodes.
*
* @param from The index of the first node
* @param to The index of the second node
* @return The index of the found edge or -1
*/
protected int findEdge(int from, int to) {
for (int i = 0; i < nEdges; i++)
if (( (edges[i].from == from) && (edges[i].to == to) ) ||
( (edges[i].from == to) && (edges[i].to == from) ) )
return i;
return -1;
}
/**
* All edges starting from the given node are aged.
* Too old edges are deleted.
*
* @param node The index of a node
* @see ComputeGNG#maxEdgeAge
*/
protected void ageEdgesOfNode(int node) {
// TODO: this is inefficient for large number of edges, perhaps keep local list of edges per node
for (int i = nEdges - 1; i > -1; i--) {
if ( (edges[i].from == node) || (edges[i].to == node) )
edges[i].age++;
if (edges[i].age > maxEdgeAge)
deleteEdge(i);
}
}
/**
* Find neighbor with the highest error.
*
* @param master The index of a node
* @return The index of a node
*/
protected int maximumErrorNeighbor(int master) {
float ws = Float.MIN_VALUE;
int wn = -1;
int n = -1;
int num = nodes[master].numNeighbors();
for (int i = 0; i < num; i++) {
n = nodes[master].neighbor(i);
if (ws < nodes[n].error) {
ws = nodes[n].error;
wn = n;
}
}
return wn;
}
public void rescaleDiscreteSignals(double x, double y) {
for (int i = 0; i < MAX_DISCRETE_SIGNALS; i++) {
discreteSignalsX[i] *= x;
discreteSignalsY[i] *= y;
}
}
/**
* Generate discrete numSignals for the given distribution.
* The result goes into the global arrays discreteSignalsX
* and discreteSignalsY .
*
* With and height are taken from panelWidth and panelHeight.
*
* @param pd The specified distribution
*/
public void initDiscreteSignals(PD pd) {
// Dimension d = getSize();
int w = panelWidth; // d.width;
int h = panelHeight; // d.height;
int kx = 1;
int ky = 1;
int l = 0;
float dSX[] = discreteSignalsX;
float dSY[] = discreteSignalsY;
log("init discrete");
if (pd != PD.DiscreteMixture) {
log("init discrete from cont");
//
// generate a finite signal set from continuous distribution
//
for (int i = 0; i < MAX_DISCRETE_SIGNALS; i++) {
getSignal(pd);
discreteSignalsX[i] = SignalX;
discreteSignalsY[i] = SignalY;
}
} else {
log("init discrete from mixture");
//
// DiscreteMixture Distribution (500 Points)
//
// scale according to app dimension
if (w > h) {
kx = w/4;
l = h;
} else {
ky = h/4;
l = w;
}
int discreteSize = 500; // size of discrete mixture distribution
dSX[0]=(float)(kx+l*0.13814); dSY[0]=(float)(ky+l*(1.0-0.29675));
dSX[1]=(float)(kx+l*0.19548); dSY[1]=(float)(ky+l*(1.0-0.09674));
dSX[2]=(float)(kx+l*0.73576); dSY[2]=(float)(ky+l*(1.0-0.86994));
dSX[3]=(float)(kx+l*0.73065); dSY[3]=(float)(ky+l*(1.0-0.19024));
dSX[4]=(float)(kx+l*0.83479); dSY[4]=(float)(ky+l*(1.0-0.34258));
dSX[5]=(float)(kx+l*0.13184); dSY[5]=(float)(ky+l*(1.0-0.56509));
dSX[6]=(float)(kx+l*0.15959); dSY[6]=(float)(ky+l*(1.0-0.59065));
dSX[7]=(float)(kx+l*0.21696); dSY[7]=(float)(ky+l*(1.0-0.1402));
dSX[8]=(float)(kx+l*0.61592); dSY[8]=(float)(ky+l*(1.0-0.16657));
dSX[9]=(float)(kx+l*0.10513); dSY[9]=(float)(ky+l*(1.0-0.21708));
dSX[10]=(float)(kx+l*0.1864); dSY[10]=(float)(ky+l*(1.0-0.1454));
dSX[11]=(float)(kx+l*0.36696); dSY[11]=(float)(ky+l*(1.0-0.74924));
dSX[12]=(float)(kx+l*0.18345); dSY[12]=(float)(ky+l*(1.0-0.80946));
dSX[13]=(float)(kx+l*0.8509); dSY[13]=(float)(ky+l*(1.0-0.38268));
dSX[14]=(float)(kx+l*0.19476); dSY[14]=(float)(ky+l*(1.0-0.74262));
dSX[15]=(float)(kx+l*0.49164); dSY[15]=(float)(ky+l*(1.0-0.65776));
dSX[16]=(float)(kx+l*0.86552); dSY[16]=(float)(ky+l*(1.0-0.38373));
dSX[17]=(float)(kx+l*0.73176); dSY[17]=(float)(ky+l*(1.0-0.84414));
dSX[18]=(float)(kx+l*0.71978); dSY[18]=(float)(ky+l*(1.0-0.86979));
dSX[19]=(float)(kx+l*0.83034); dSY[19]=(float)(ky+l*(1.0-0.36613));
dSX[20]=(float)(kx+l*0.39886); dSY[20]=(float)(ky+l*(1.0-0.71479));
dSX[21]=(float)(kx+l*0.09955); dSY[21]=(float)(ky+l*(1.0-0.20342));
dSX[22]=(float)(kx+l*0.07091); dSY[22]=(float)(ky+l*(1.0-0.17197));
dSX[23]=(float)(kx+l*0.21896); dSY[23]=(float)(ky+l*(1.0-0.10398));
dSX[24]=(float)(kx+l*0.72465); dSY[24]=(float)(ky+l*(1.0-0.13984));
dSX[25]=(float)(kx+l*0.71034); dSY[25]=(float)(ky+l*(1.0-0.87981));
dSX[26]=(float)(kx+l*0.83547); dSY[26]=(float)(ky+l*(1.0-0.36065));
dSX[27]=(float)(kx+l*0.13907); dSY[27]=(float)(ky+l*(1.0-0.56451));
dSX[28]=(float)(kx+l*0.62124); dSY[28]=(float)(ky+l*(1.0-0.20175));
dSX[29]=(float)(kx+l*0.65543); dSY[29]=(float)(ky+l*(1.0-0.17331));
dSX[30]=(float)(kx+l*0.72349); dSY[30]=(float)(ky+l*(1.0-0.14375));
dSX[31]=(float)(kx+l*0.82495); dSY[31]=(float)(ky+l*(1.0-0.40116));
dSX[32]=(float)(kx+l*0.76586); dSY[32]=(float)(ky+l*(1.0-0.82376));
dSX[33]=(float)(kx+l*0.24648); dSY[33]=(float)(ky+l*(1.0-0.11987));
dSX[34]=(float)(kx+l*0.14817); dSY[34]=(float)(ky+l*(1.0-0.59985));
dSX[35]=(float)(kx+l*0.82663); dSY[35]=(float)(ky+l*(1.0-0.38964));
dSX[36]=(float)(kx+l*0.37131); dSY[36]=(float)(ky+l*(1.0-0.72726));
dSX[37]=(float)(kx+l*0.12176); dSY[37]=(float)(ky+l*(1.0-0.60139));
dSX[38]=(float)(kx+l*0.73587); dSY[38]=(float)(ky+l*(1.0-0.86952));
dSX[39]=(float)(kx+l*0.59645); dSY[39]=(float)(ky+l*(1.0-0.21302));
dSX[40]=(float)(kx+l*0.39489); dSY[40]=(float)(ky+l*(1.0-0.63452));
dSX[41]=(float)(kx+l*0.234); dSY[41]=(float)(ky+l*(1.0-0.10385));
dSX[42]=(float)(kx+l*0.51314); dSY[42]=(float)(ky+l*(1.0-0.67151));
dSX[43]=(float)(kx+l*0.13499); dSY[43]=(float)(ky+l*(1.0-0.56896));
dSX[44]=(float)(kx+l*0.10815); dSY[44]=(float)(ky+l*(1.0-0.62515));
dSX[45]=(float)(kx+l*0.35487); dSY[45]=(float)(ky+l*(1.0-0.65635));
dSX[46]=(float)(kx+l*0.13939); dSY[46]=(float)(ky+l*(1.0-0.24579));
dSX[47]=(float)(kx+l*0.22087); dSY[47]=(float)(ky+l*(1.0-0.20651));
dSX[48]=(float)(kx+l*0.12274); dSY[48]=(float)(ky+l*(1.0-0.61131));
dSX[49]=(float)(kx+l*0.47888); dSY[49]=(float)(ky+l*(1.0-0.65166));
dSX[50]=(float)(kx+l*0.18836); dSY[50]=(float)(ky+l*(1.0-0.6895));
dSX[51]=(float)(kx+l*0.2511); dSY[51]=(float)(ky+l*(1.0-0.12476));
dSX[52]=(float)(kx+l*0.84242); dSY[52]=(float)(ky+l*(1.0-0.3685));
dSX[53]=(float)(kx+l*0.70824); dSY[53]=(float)(ky+l*(1.0-0.18571));
dSX[54]=(float)(kx+l*0.2548); dSY[54]=(float)(ky+l*(1.0-0.77552));
dSX[55]=(float)(kx+l*0.3659); dSY[55]=(float)(ky+l*(1.0-0.64852));
dSX[56]=(float)(kx+l*0.78094); dSY[56]=(float)(ky+l*(1.0-0.37826));
dSX[57]=(float)(kx+l*0.34205); dSY[57]=(float)(ky+l*(1.0-0.7295));
dSX[58]=(float)(kx+l*0.83349); dSY[58]=(float)(ky+l*(1.0-0.37511));
dSX[59]=(float)(kx+l*0.35477); dSY[59]=(float)(ky+l*(1.0-0.68483));
dSX[60]=(float)(kx+l*0.13761); dSY[60]=(float)(ky+l*(1.0-0.17267));
dSX[61]=(float)(kx+l*0.46041); dSY[61]=(float)(ky+l*(1.0-0.72594));
dSX[62]=(float)(kx+l*0.12945); dSY[62]=(float)(ky+l*(1.0-0.58863));
dSX[63]=(float)(kx+l*0.27379); dSY[63]=(float)(ky+l*(1.0-0.14071));
dSX[64]=(float)(kx+l*0.4097); dSY[64]=(float)(ky+l*(1.0-0.77705));
dSX[65]=(float)(kx+l*0.7175); dSY[65]=(float)(ky+l*(1.0-0.87696));
dSX[66]=(float)(kx+l*0.43969); dSY[66]=(float)(ky+l*(1.0-0.66972));
dSX[67]=(float)(kx+l*0.48588); dSY[67]=(float)(ky+l*(1.0-0.63899));
dSX[68]=(float)(kx+l*0.69263); dSY[68]=(float)(ky+l*(1.0-0.20386));
dSX[69]=(float)(kx+l*0.7374); dSY[69]=(float)(ky+l*(1.0-0.8667));
dSX[70]=(float)(kx+l*0.67306); dSY[70]=(float)(ky+l*(1.0-0.18347));
dSX[71]=(float)(kx+l*0.21203); dSY[71]=(float)(ky+l*(1.0-0.12508));
dSX[72]=(float)(kx+l*0.48821); dSY[72]=(float)(ky+l*(1.0-0.67574));
dSX[73]=(float)(kx+l*0.45742); dSY[73]=(float)(ky+l*(1.0-0.67679));
dSX[74]=(float)(kx+l*0.67982); dSY[74]=(float)(ky+l*(1.0-0.1421));
dSX[75]=(float)(kx+l*0.13429); dSY[75]=(float)(ky+l*(1.0-0.56728));
dSX[76]=(float)(kx+l*0.2402); dSY[76]=(float)(ky+l*(1.0-0.76521));
dSX[77]=(float)(kx+l*0.15482); dSY[77]=(float)(ky+l*(1.0-0.178));
dSX[78]=(float)(kx+l*0.71594); dSY[78]=(float)(ky+l*(1.0-0.15844));
dSX[79]=(float)(kx+l*0.10534); dSY[79]=(float)(ky+l*(1.0-0.59961));
dSX[80]=(float)(kx+l*0.44167); dSY[80]=(float)(ky+l*(1.0-0.69823));
dSX[81]=(float)(kx+l*0.46529); dSY[81]=(float)(ky+l*(1.0-0.70682));
dSX[82]=(float)(kx+l*0.13842); dSY[82]=(float)(ky+l*(1.0-0.56618));
dSX[83]=(float)(kx+l*0.09876); dSY[83]=(float)(ky+l*(1.0-0.5795));
dSX[84]=(float)(kx+l*0.12101); dSY[84]=(float)(ky+l*(1.0-0.57408));
dSX[85]=(float)(kx+l*0.44963); dSY[85]=(float)(ky+l*(1.0-0.74847));
dSX[86]=(float)(kx+l*0.12532); dSY[86]=(float)(ky+l*(1.0-0.56478));
dSX[87]=(float)(kx+l*0.18264); dSY[87]=(float)(ky+l*(1.0-0.77186));
dSX[88]=(float)(kx+l*0.80443); dSY[88]=(float)(ky+l*(1.0-0.35896));
dSX[89]=(float)(kx+l*0.72038); dSY[89]=(float)(ky+l*(1.0-0.90205));
dSX[90]=(float)(kx+l*0.24934); dSY[90]=(float)(ky+l*(1.0-0.77047));
dSX[91]=(float)(kx+l*0.35552); dSY[91]=(float)(ky+l*(1.0-0.70131));
dSX[92]=(float)(kx+l*0.49591); dSY[92]=(float)(ky+l*(1.0-0.71126));
dSX[93]=(float)(kx+l*0.36426); dSY[93]=(float)(ky+l*(1.0-0.72803));
dSX[94]=(float)(kx+l*0.21113); dSY[94]=(float)(ky+l*(1.0-0.08745));
dSX[95]=(float)(kx+l*0.33412); dSY[95]=(float)(ky+l*(1.0-0.68345));
dSX[96]=(float)(kx+l*0.17158); dSY[96]=(float)(ky+l*(1.0-0.226));
dSX[97]=(float)(kx+l*0.69135); dSY[97]=(float)(ky+l*(1.0-0.26172));
dSX[98]=(float)(kx+l*0.80362); dSY[98]=(float)(ky+l*(1.0-0.34908));
dSX[99]=(float)(kx+l*0.49367); dSY[99]=(float)(ky+l*(1.0-0.61372));
dSX[100]=(float)(kx+l*0.67809); dSY[100]=(float)(ky+l*(1.0-0.16071));
dSX[101]=(float)(kx+l*0.42288); dSY[101]=(float)(ky+l*(1.0-0.7547));
dSX[102]=(float)(kx+l*0.21535); dSY[102]=(float)(ky+l*(1.0-0.71766));
dSX[103]=(float)(kx+l*0.26248); dSY[103]=(float)(ky+l*(1.0-0.0794));
dSX[104]=(float)(kx+l*0.65766); dSY[104]=(float)(ky+l*(1.0-0.11433));
dSX[105]=(float)(kx+l*0.81799); dSY[105]=(float)(ky+l*(1.0-0.36416));
dSX[106]=(float)(kx+l*0.80867); dSY[106]=(float)(ky+l*(1.0-0.39382));
dSX[107]=(float)(kx+l*0.2401); dSY[107]=(float)(ky+l*(1.0-0.83207));
dSX[108]=(float)(kx+l*0.83016); dSY[108]=(float)(ky+l*(1.0-0.37551));
dSX[109]=(float)(kx+l*0.30746); dSY[109]=(float)(ky+l*(1.0-0.78597));
dSX[110]=(float)(kx+l*0.22122); dSY[110]=(float)(ky+l*(1.0-0.19961));
dSX[111]=(float)(kx+l*0.81422); dSY[111]=(float)(ky+l*(1.0-0.39008));
dSX[112]=(float)(kx+l*0.28025); dSY[112]=(float)(ky+l*(1.0-0.16485));
dSX[113]=(float)(kx+l*0.42936); dSY[113]=(float)(ky+l*(1.0-0.70449));
dSX[114]=(float)(kx+l*0.20721); dSY[114]=(float)(ky+l*(1.0-0.79412));
dSX[115]=(float)(kx+l*0.1023); dSY[115]=(float)(ky+l*(1.0-0.59687));
dSX[116]=(float)(kx+l*0.49873); dSY[116]=(float)(ky+l*(1.0-0.68088));
dSX[117]=(float)(kx+l*0.44373); dSY[117]=(float)(ky+l*(1.0-0.60472));
dSX[118]=(float)(kx+l*0.12955); dSY[118]=(float)(ky+l*(1.0-0.58045));
dSX[119]=(float)(kx+l*0.40319); dSY[119]=(float)(ky+l*(1.0-0.64087));
dSX[120]=(float)(kx+l*0.39597); dSY[120]=(float)(ky+l*(1.0-0.74223));
dSX[121]=(float)(kx+l*0.37318); dSY[121]=(float)(ky+l*(1.0-0.74561));
dSX[122]=(float)(kx+l*0.48026); dSY[122]=(float)(ky+l*(1.0-0.65002));
dSX[123]=(float)(kx+l*0.09824); dSY[123]=(float)(ky+l*(1.0-0.15969));
dSX[124]=(float)(kx+l*0.68454); dSY[124]=(float)(ky+l*(1.0-0.17986));
dSX[125]=(float)(kx+l*0.11659); dSY[125]=(float)(ky+l*(1.0-0.30008));
dSX[126]=(float)(kx+l*0.73836); dSY[126]=(float)(ky+l*(1.0-0.87819));
dSX[127]=(float)(kx+l*0.37924); dSY[127]=(float)(ky+l*(1.0-0.72885));
dSX[128]=(float)(kx+l*0.07252); dSY[128]=(float)(ky+l*(1.0-0.21803));
dSX[129]=(float)(kx+l*0.22104); dSY[129]=(float)(ky+l*(1.0-0.81961));
dSX[130]=(float)(kx+l*0.23872); dSY[130]=(float)(ky+l*(1.0-0.06629));
dSX[131]=(float)(kx+l*0.27114); dSY[131]=(float)(ky+l*(1.0-0.77851));
dSX[132]=(float)(kx+l*0.84307); dSY[132]=(float)(ky+l*(1.0-0.35729));
dSX[133]=(float)(kx+l*0.83856); dSY[133]=(float)(ky+l*(1.0-0.38892));
dSX[134]=(float)(kx+l*0.84041); dSY[134]=(float)(ky+l*(1.0-0.33806));
dSX[135]=(float)(kx+l*0.72441); dSY[135]=(float)(ky+l*(1.0-0.84423));
dSX[136]=(float)(kx+l*0.45169); dSY[136]=(float)(ky+l*(1.0-0.66888));
dSX[137]=(float)(kx+l*0.7291); dSY[137]=(float)(ky+l*(1.0-0.85748));
dSX[138]=(float)(kx+l*0.38792); dSY[138]=(float)(ky+l*(1.0-0.74045));
dSX[139]=(float)(kx+l*0.69006); dSY[139]=(float)(ky+l*(1.0-0.88995));
dSX[140]=(float)(kx+l*0.09004); dSY[140]=(float)(ky+l*(1.0-0.57847));
dSX[141]=(float)(kx+l*0.20986); dSY[141]=(float)(ky+l*(1.0-0.21552));
dSX[142]=(float)(kx+l*0.22969); dSY[142]=(float)(ky+l*(1.0-0.79372));
dSX[143]=(float)(kx+l*0.2407); dSY[143]=(float)(ky+l*(1.0-0.78147));
dSX[144]=(float)(kx+l*0.83483); dSY[144]=(float)(ky+l*(1.0-0.35725));
dSX[145]=(float)(kx+l*0.74069); dSY[145]=(float)(ky+l*(1.0-0.87034));
dSX[146]=(float)(kx+l*0.53127); dSY[146]=(float)(ky+l*(1.0-0.69099));
dSX[147]=(float)(kx+l*0.73562); dSY[147]=(float)(ky+l*(1.0-0.89203));
dSX[148]=(float)(kx+l*0.22449); dSY[148]=(float)(ky+l*(1.0-0.14296));
dSX[149]=(float)(kx+l*0.74473); dSY[149]=(float)(ky+l*(1.0-0.85085));
dSX[150]=(float)(kx+l*0.80492); dSY[150]=(float)(ky+l*(1.0-0.40119));
dSX[151]=(float)(kx+l*0.66545); dSY[151]=(float)(ky+l*(1.0-0.14658));
dSX[152]=(float)(kx+l*0.74401); dSY[152]=(float)(ky+l*(1.0-0.88545));
dSX[153]=(float)(kx+l*0.16486); dSY[153]=(float)(ky+l*(1.0-0.81768));
dSX[154]=(float)(kx+l*0.10909); dSY[154]=(float)(ky+l*(1.0-0.58963));
dSX[155]=(float)(kx+l*0.36812); dSY[155]=(float)(ky+l*(1.0-0.71451));
dSX[156]=(float)(kx+l*0.77083); dSY[156]=(float)(ky+l*(1.0-0.86754));
dSX[157]=(float)(kx+l*0.19709); dSY[157]=(float)(ky+l*(1.0-0.16813));
dSX[158]=(float)(kx+l*0.08257); dSY[158]=(float)(ky+l*(1.0-0.57901));
dSX[159]=(float)(kx+l*0.81561); dSY[159]=(float)(ky+l*(1.0-0.38789));
dSX[160]=(float)(kx+l*0.11613); dSY[160]=(float)(ky+l*(1.0-0.61403));
dSX[161]=(float)(kx+l*0.16391); dSY[161]=(float)(ky+l*(1.0-0.10041));
dSX[162]=(float)(kx+l*0.36024); dSY[162]=(float)(ky+l*(1.0-0.75178));
dSX[163]=(float)(kx+l*0.73822); dSY[163]=(float)(ky+l*(1.0-0.84884));
dSX[164]=(float)(kx+l*0.22963); dSY[164]=(float)(ky+l*(1.0-0.11442));
dSX[165]=(float)(kx+l*0.01152); dSY[165]=(float)(ky+l*(1.0-0.27939));
dSX[166]=(float)(kx+l*0.74314); dSY[166]=(float)(ky+l*(1.0-0.87522));
dSX[167]=(float)(kx+l*0.22871); dSY[167]=(float)(ky+l*(1.0-0.134));
dSX[168]=(float)(kx+l*0.14996); dSY[168]=(float)(ky+l*(1.0-0.54459));
dSX[169]=(float)(kx+l*0.14354); dSY[169]=(float)(ky+l*(1.0-0.25589));
dSX[170]=(float)(kx+l*0.0779); dSY[170]=(float)(ky+l*(1.0-0.2636));
dSX[171]=(float)(kx+l*0.13208); dSY[171]=(float)(ky+l*(1.0-0.28005));
dSX[172]=(float)(kx+l*0.2498); dSY[172]=(float)(ky+l*(1.0-0.75765));
dSX[173]=(float)(kx+l*0.30859); dSY[173]=(float)(ky+l*(1.0-0.08592));
dSX[174]=(float)(kx+l*0.03277); dSY[174]=(float)(ky+l*(1.0-0.25141));
dSX[175]=(float)(kx+l*0.69026); dSY[175]=(float)(ky+l*(1.0-0.11579));
dSX[176]=(float)(kx+l*0.70569); dSY[176]=(float)(ky+l*(1.0-0.20655));
dSX[177]=(float)(kx+l*0.19796); dSY[177]=(float)(ky+l*(1.0-0.1327));
dSX[178]=(float)(kx+l*0.10402); dSY[178]=(float)(ky+l*(1.0-0.18623));
dSX[179]=(float)(kx+l*0.20623); dSY[179]=(float)(ky+l*(1.0-0.17315));
dSX[180]=(float)(kx+l*0.14383); dSY[180]=(float)(ky+l*(1.0-0.16819));
dSX[181]=(float)(kx+l*0.43416); dSY[181]=(float)(ky+l*(1.0-0.81161));
dSX[182]=(float)(kx+l*0.21801); dSY[182]=(float)(ky+l*(1.0-0.1926));
dSX[183]=(float)(kx+l*0.80582); dSY[183]=(float)(ky+l*(1.0-0.40684));
dSX[184]=(float)(kx+l*0.47273); dSY[184]=(float)(ky+l*(1.0-0.66746));
dSX[185]=(float)(kx+l*0.72923); dSY[185]=(float)(ky+l*(1.0-0.91807));
dSX[186]=(float)(kx+l*0.21609); dSY[186]=(float)(ky+l*(1.0-0.14719));
dSX[187]=(float)(kx+l*0.61592); dSY[187]=(float)(ky+l*(1.0-0.17603));
dSX[188]=(float)(kx+l*0.25956); dSY[188]=(float)(ky+l*(1.0-0.74824));
dSX[189]=(float)(kx+l*0.10157); dSY[189]=(float)(ky+l*(1.0-0.25437));
dSX[190]=(float)(kx+l*0.34822); dSY[190]=(float)(ky+l*(1.0-0.74119));
dSX[191]=(float)(kx+l*0.37535); dSY[191]=(float)(ky+l*(1.0-0.68263));
dSX[192]=(float)(kx+l*0.11609); dSY[192]=(float)(ky+l*(1.0-0.25491));
dSX[193]=(float)(kx+l*0.84751); dSY[193]=(float)(ky+l*(1.0-0.36326));
dSX[194]=(float)(kx+l*0.48434); dSY[194]=(float)(ky+l*(1.0-0.71852));
dSX[195]=(float)(kx+l*0.82894); dSY[195]=(float)(ky+l*(1.0-0.38072));
dSX[196]=(float)(kx+l*0.23618); dSY[196]=(float)(ky+l*(1.0-0.78797));
dSX[197]=(float)(kx+l*0.70894); dSY[197]=(float)(ky+l*(1.0-0.84481));
dSX[198]=(float)(kx+l*0.21377); dSY[198]=(float)(ky+l*(1.0-0.08697));
dSX[199]=(float)(kx+l*0.08777); dSY[199]=(float)(ky+l*(1.0-0.23077));
dSX[200]=(float)(kx+l*0.4627); dSY[200]=(float)(ky+l*(1.0-0.68689));
dSX[201]=(float)(kx+l*0.1064); dSY[201]=(float)(ky+l*(1.0-0.13423));
dSX[202]=(float)(kx+l*0.34044); dSY[202]=(float)(ky+l*(1.0-0.71728));
dSX[203]=(float)(kx+l*0.14377); dSY[203]=(float)(ky+l*(1.0-0.10488));
dSX[204]=(float)(kx+l*0.83586); dSY[204]=(float)(ky+l*(1.0-0.39654));
dSX[205]=(float)(kx+l*0.23719); dSY[205]=(float)(ky+l*(1.0-0.75877));
dSX[206]=(float)(kx+l*0.72909); dSY[206]=(float)(ky+l*(1.0-0.83794));
dSX[207]=(float)(kx+l*0.11163); dSY[207]=(float)(ky+l*(1.0-0.57717));
dSX[208]=(float)(kx+l*0.82082); dSY[208]=(float)(ky+l*(1.0-0.38887));
dSX[209]=(float)(kx+l*0.23973); dSY[209]=(float)(ky+l*(1.0-0.09762));
dSX[210]=(float)(kx+l*0.18049); dSY[210]=(float)(ky+l*(1.0-0.7213));
dSX[211]=(float)(kx+l*0.17251); dSY[211]=(float)(ky+l*(1.0-0.06261));
dSX[212]=(float)(kx+l*0.73943); dSY[212]=(float)(ky+l*(1.0-0.1515));
dSX[213]=(float)(kx+l*0.12257); dSY[213]=(float)(ky+l*(1.0-0.21737));
dSX[214]=(float)(kx+l*0.72598); dSY[214]=(float)(ky+l*(1.0-0.87021));
dSX[215]=(float)(kx+l*0.7244); dSY[215]=(float)(ky+l*(1.0-0.88142));
dSX[216]=(float)(kx+l*0.21058); dSY[216]=(float)(ky+l*(1.0-0.83842));
dSX[217]=(float)(kx+l*0.34401); dSY[217]=(float)(ky+l*(1.0-0.72108));
dSX[218]=(float)(kx+l*0.65233); dSY[218]=(float)(ky+l*(1.0-0.15241));
dSX[219]=(float)(kx+l*0.1184); dSY[219]=(float)(ky+l*(1.0-0.59815));
dSX[220]=(float)(kx+l*0.20673); dSY[220]=(float)(ky+l*(1.0-0.09814));
dSX[221]=(float)(kx+l*0.65673); dSY[221]=(float)(ky+l*(1.0-0.19377));
dSX[222]=(float)(kx+l*0.46674); dSY[222]=(float)(ky+l*(1.0-0.7408));
dSX[223]=(float)(kx+l*0.14444); dSY[223]=(float)(ky+l*(1.0-0.18892));
dSX[224]=(float)(kx+l*0.44631); dSY[224]=(float)(ky+l*(1.0-0.72023));
dSX[225]=(float)(kx+l*0.18501); dSY[225]=(float)(ky+l*(1.0-0.81523));
dSX[226]=(float)(kx+l*0.67013); dSY[226]=(float)(ky+l*(1.0-0.17383));
dSX[227]=(float)(kx+l*0.21007); dSY[227]=(float)(ky+l*(1.0-0.11003));
dSX[228]=(float)(kx+l*0.28895); dSY[228]=(float)(ky+l*(1.0-0.79667));
dSX[229]=(float)(kx+l*0.355); dSY[229]=(float)(ky+l*(1.0-0.77679));
dSX[230]=(float)(kx+l*0.8031); dSY[230]=(float)(ky+l*(1.0-0.40707));
dSX[231]=(float)(kx+l*0.20507); dSY[231]=(float)(ky+l*(1.0-0.23746));
dSX[232]=(float)(kx+l*0.2091); dSY[232]=(float)(ky+l*(1.0-0.1445));
dSX[233]=(float)(kx+l*0.69395); dSY[233]=(float)(ky+l*(1.0-0.87292));
dSX[234]=(float)(kx+l*0.26225); dSY[234]=(float)(ky+l*(1.0-0.83517));
dSX[235]=(float)(kx+l*0.46057); dSY[235]=(float)(ky+l*(1.0-0.66066));
dSX[236]=(float)(kx+l*0.46715); dSY[236]=(float)(ky+l*(1.0-0.62083));
dSX[237]=(float)(kx+l*0.15991); dSY[237]=(float)(ky+l*(1.0-0.16164));
dSX[238]=(float)(kx+l*0.66818); dSY[238]=(float)(ky+l*(1.0-0.18336));
dSX[239]=(float)(kx+l*0.1206); dSY[239]=(float)(ky+l*(1.0-0.20415));
dSX[240]=(float)(kx+l*0.11134); dSY[240]=(float)(ky+l*(1.0-0.17899));
dSX[241]=(float)(kx+l*0.81705); dSY[241]=(float)(ky+l*(1.0-0.3876));
dSX[242]=(float)(kx+l*0.16158); dSY[242]=(float)(ky+l*(1.0-0.58197));
dSX[243]=(float)(kx+l*0.71638); dSY[243]=(float)(ky+l*(1.0-0.92072));
dSX[244]=(float)(kx+l*0.70824); dSY[244]=(float)(ky+l*(1.0-0.86881));
dSX[245]=(float)(kx+l*0.21828); dSY[245]=(float)(ky+l*(1.0-0.07292));
dSX[246]=(float)(kx+l*0.23573); dSY[246]=(float)(ky+l*(1.0-0.05748));
dSX[247]=(float)(kx+l*0.11584); dSY[247]=(float)(ky+l*(1.0-0.70939));
dSX[248]=(float)(kx+l*0.1235); dSY[248]=(float)(ky+l*(1.0-0.23567));
dSX[249]=(float)(kx+l*0.18015); dSY[249]=(float)(ky+l*(1.0-0.73396));
dSX[250]=(float)(kx+l*0.04505); dSY[250]=(float)(ky+l*(1.0-0.22103));
dSX[251]=(float)(kx+l*0.75712); dSY[251]=(float)(ky+l*(1.0-0.89093));
dSX[252]=(float)(kx+l*0.51855); dSY[252]=(float)(ky+l*(1.0-0.68719));
dSX[253]=(float)(kx+l*0.20628); dSY[253]=(float)(ky+l*(1.0-0.78227));
dSX[254]=(float)(kx+l*0.3027); dSY[254]=(float)(ky+l*(1.0-0.74326));
dSX[255]=(float)(kx+l*0.72344); dSY[255]=(float)(ky+l*(1.0-0.86115));
dSX[256]=(float)(kx+l*0.7823); dSY[256]=(float)(ky+l*(1.0-0.40698));
dSX[257]=(float)(kx+l*0.80725); dSY[257]=(float)(ky+l*(1.0-0.36859));
dSX[258]=(float)(kx+l*0.22767); dSY[258]=(float)(ky+l*(1.0-0.72875));
dSX[259]=(float)(kx+l*0.8389); dSY[259]=(float)(ky+l*(1.0-0.36071));
dSX[260]=(float)(kx+l*0.15643); dSY[260]=(float)(ky+l*(1.0-0.1861));
dSX[261]=(float)(kx+l*0.70301); dSY[261]=(float)(ky+l*(1.0-0.13106));
dSX[262]=(float)(kx+l*0.27509); dSY[262]=(float)(ky+l*(1.0-0.07504));
dSX[263]=(float)(kx+l*0.26088); dSY[263]=(float)(ky+l*(1.0-0.7257));
dSX[264]=(float)(kx+l*0.21206); dSY[264]=(float)(ky+l*(1.0-0.75771));
dSX[265]=(float)(kx+l*0.13805); dSY[265]=(float)(ky+l*(1.0-0.58384));
dSX[266]=(float)(kx+l*0.77447); dSY[266]=(float)(ky+l*(1.0-0.88097));
dSX[267]=(float)(kx+l*0.24243); dSY[267]=(float)(ky+l*(1.0-0.76475));
dSX[268]=(float)(kx+l*0.22454); dSY[268]=ky+l; // -0.01632
dSX[269]=(float)(kx+l*0.46329); dSY[269]=(float)(ky+l*(1.0-0.66386));
dSX[270]=(float)(kx+l*0.42856); dSY[270]=(float)(ky+l*(1.0-0.77059));
dSX[271]=(float)(kx+l*0.09912); dSY[271]=(float)(ky+l*(1.0-0.23061));
dSX[272]=(float)(kx+l*0.40031); dSY[272]=(float)(ky+l*(1.0-0.7123));
dSX[273]=(float)(kx+l*0.41085); dSY[273]=(float)(ky+l*(1.0-0.68234));
dSX[274]=(float)(kx+l*0.16843); dSY[274]=(float)(ky+l*(1.0-0.21484));
dSX[275]=(float)(kx+l*0.19902); dSY[275]=(float)(ky+l*(1.0-0.74001));
dSX[276]=(float)(kx+l*0.23913); dSY[276]=(float)(ky+l*(1.0-0.83891));
dSX[277]=(float)(kx+l*0.52281); dSY[277]=(float)(ky+l*(1.0-0.68538));
dSX[278]=(float)(kx+l*0.77193); dSY[278]=(float)(ky+l*(1.0-0.85292));
dSX[279]=(float)(kx+l*0.62099); dSY[279]=(float)(ky+l*(1.0-0.1954));
dSX[280]=(float)(kx+l*0.76508); dSY[280]=(float)(ky+l*(1.0-0.88685));
dSX[281]=(float)(kx+l*0.17655); dSY[281]=(float)(ky+l*(1.0-0.19809));
dSX[282]=(float)(kx+l*0.25752); dSY[282]=(float)(ky+l*(1.0-0.14649));
dSX[283]=(float)(kx+l*0.41938); dSY[283]=(float)(ky+l*(1.0-0.66025));
dSX[284]=(float)(kx+l*0.64649); dSY[284]=(float)(ky+l*(1.0-0.16984));
dSX[285]=(float)(kx+l*0.83039); dSY[285]=(float)(ky+l*(1.0-0.36848));
dSX[286]=(float)(kx+l*0.47482); dSY[286]=(float)(ky+l*(1.0-0.75725));
dSX[287]=(float)(kx+l*0.36224); dSY[287]=(float)(ky+l*(1.0-0.72407));
dSX[288]=(float)(kx+l*0.41691); dSY[288]=(float)(ky+l*(1.0-0.76211));
dSX[289]=(float)(kx+l*0.71197); dSY[289]=(float)(ky+l*(1.0-0.88301));
dSX[290]=(float)(kx+l*0.38875); dSY[290]=(float)(ky+l*(1.0-0.66923));
dSX[291]=(float)(kx+l*0.65122); dSY[291]=(float)(ky+l*(1.0-0.2006));
dSX[292]=(float)(kx+l*0.14963); dSY[292]=(float)(ky+l*(1.0-0.58176));
dSX[293]=(float)(kx+l*0.12702); dSY[293]=(float)(ky+l*(1.0-0.20527));
dSX[294]=(float)(kx+l*0.21471); dSY[294]=(float)(ky+l*(1.0-0.80336));
dSX[295]=(float)(kx+l*0.1117); dSY[295]=(float)(ky+l*(1.0-0.58565));
dSX[296]=(float)(kx+l*0.21964); dSY[296]=(float)(ky+l*(1.0-0.05787));
dSX[297]=(float)(kx+l*0.52603); dSY[297]=(float)(ky+l*(1.0-0.68563));
dSX[298]=(float)(kx+l*0.2513); dSY[298]=(float)(ky+l*(1.0-0.11038));
dSX[299]=(float)(kx+l*0.23048); dSY[299]=(float)(ky+l*(1.0-0.81628));
dSX[300]=(float)(kx+l*0.07918); dSY[300]=(float)(ky+l*(1.0-0.59745));
dSX[301]=(float)(kx+l*0.39107); dSY[301]=(float)(ky+l*(1.0-0.70391));
dSX[302]=(float)(kx+l*0.1921); dSY[302]=(float)(ky+l*(1.0-0.75531));
dSX[303]=(float)(kx+l*0.69606); dSY[303]=(float)(ky+l*(1.0-0.21785));
dSX[304]=(float)(kx+l*0.14619); dSY[304]=(float)(ky+l*(1.0-0.57905));
dSX[305]=(float)(kx+l*0.79628); dSY[305]=(float)(ky+l*(1.0-0.3461));
dSX[306]=(float)(kx+l*0.26276); dSY[306]=(float)(ky+l*(1.0-0.17608));
dSX[307]=(float)(kx+l*0.32383); dSY[307]=(float)(ky+l*(1.0-0.74517));
dSX[308]=(float)(kx+l*0.71259); dSY[308]=(float)(ky+l*(1.0-0.85462));
dSX[309]=(float)(kx+l*0.11917); dSY[309]=(float)(ky+l*(1.0-0.25115));
dSX[310]=(float)(kx+l*0.15771); dSY[310]=(float)(ky+l*(1.0-0.5723));
dSX[311]=(float)(kx+l*0.74207); dSY[311]=(float)(ky+l*(1.0-0.86498));
dSX[312]=(float)(kx+l*0.30246); dSY[312]=(float)(ky+l*(1.0-0.66994));
dSX[313]=(float)(kx+l*0.20864); dSY[313]=(float)(ky+l*(1.0-0.16323));
dSX[314]=(float)(kx+l*0.1412); dSY[314]=(float)(ky+l*(1.0-0.56028));
dSX[315]=(float)(kx+l*0.82053); dSY[315]=(float)(ky+l*(1.0-0.35693));
dSX[316]=(float)(kx+l*0.22989); dSY[316]=(float)(ky+l*(1.0-0.81021));
dSX[317]=(float)(kx+l*0.10676); dSY[317]=(float)(ky+l*(1.0-0.20945));
dSX[318]=(float)(kx+l*0.24867); dSY[318]=(float)(ky+l*(1.0-0.13241));
dSX[319]=(float)(kx+l*0.18081); dSY[319]=(float)(ky+l*(1.0-0.77961));
dSX[320]=(float)(kx+l*0.8051); dSY[320]=(float)(ky+l*(1.0-0.37642));
dSX[321]=(float)(kx+l*0.71303); dSY[321]=(float)(ky+l*(1.0-0.87868));
dSX[322]=(float)(kx+l*0.20502); dSY[322]=(float)(ky+l*(1.0-0.20587));
dSX[323]=(float)(kx+l*0.47605); dSY[323]=(float)(ky+l*(1.0-0.68292));
dSX[324]=(float)(kx+l*0.20975); dSY[324]=(float)(ky+l*(1.0-0.13444));
dSX[325]=(float)(kx+l*0.7098); dSY[325]=(float)(ky+l*(1.0-0.85967));
dSX[326]=(float)(kx+l*0.19912); dSY[326]=(float)(ky+l*(1.0-0.11887));
dSX[327]=(float)(kx+l*0.21338); dSY[327]=(float)(ky+l*(1.0-0.15242));
dSX[328]=(float)(kx+l*0.0816); dSY[328]=(float)(ky+l*(1.0-0.20505));
dSX[329]=(float)(kx+l*0.81617); dSY[329]=(float)(ky+l*(1.0-0.37632));
dSX[330]=(float)(kx+l*0.11072); dSY[330]=(float)(ky+l*(1.0-0.1742));
dSX[331]=(float)(kx+l*0.44663); dSY[331]=(float)(ky+l*(1.0-0.7283));
dSX[332]=(float)(kx+l*0.43758); dSY[332]=(float)(ky+l*(1.0-0.7116));
dSX[333]=(float)(kx+l*0.11169); dSY[333]=(float)(ky+l*(1.0-0.58286));
dSX[334]=(float)(kx+l*0.21739); dSY[334]=(float)(ky+l*(1.0-0.808));
dSX[335]=(float)(kx+l*0.11504); dSY[335]=(float)(ky+l*(1.0-0.58542));
dSX[336]=(float)(kx+l*0.22232); dSY[336]=(float)(ky+l*(1.0-0.10244));
dSX[337]=(float)(kx+l*0.13277); dSY[337]=(float)(ky+l*(1.0-0.5679));
dSX[338]=(float)(kx+l*0.41598); dSY[338]=(float)(ky+l*(1.0-0.73469));
dSX[339]=(float)(kx+l*0.23372); dSY[339]=(float)(ky+l*(1.0-0.76431));
dSX[340]=(float)(kx+l*0.32057); dSY[340]=(float)(ky+l*(1.0-0.75133));
dSX[341]=(float)(kx+l*0.82525); dSY[341]=(float)(ky+l*(1.0-0.39564));
dSX[342]=(float)(kx+l*0.15967); dSY[342]=(float)(ky+l*(1.0-0.17686));
dSX[343]=(float)(kx+l*0.65594); dSY[343]=(float)(ky+l*(1.0-0.90155));
dSX[344]=(float)(kx+l*0.71754); dSY[344]=(float)(ky+l*(1.0-0.87787));
dSX[345]=(float)(kx+l*0.11191); dSY[345]=(float)(ky+l*(1.0-0.59932));
dSX[346]=(float)(kx+l*0.2125); dSY[346]=(float)(ky+l*(1.0-0.05011));
dSX[347]=(float)(kx+l*0.21381); dSY[347]=(float)(ky+l*(1.0-0.13874));
dSX[348]=(float)(kx+l*0.32597); dSY[348]=(float)(ky+l*(1.0-0.702));
dSX[349]=(float)(kx+l*0.84447); dSY[349]=(float)(ky+l*(1.0-0.377));
dSX[350]=(float)(kx+l*0.23257); dSY[350]=(float)(ky+l*(1.0-0.0836));
dSX[351]=(float)(kx+l*0.09849); dSY[351]=(float)(ky+l*(1.0-0.15117));
dSX[352]=(float)(kx+l*0.25526); dSY[352]=(float)(ky+l*(1.0-0.156));
dSX[353]=(float)(kx+l*0.46334); dSY[353]=(float)(ky+l*(1.0-0.69123));
dSX[354]=(float)(kx+l*0.48943); dSY[354]=(float)(ky+l*(1.0-0.75123));
dSX[355]=(float)(kx+l*0.7088); dSY[355]=(float)(ky+l*(1.0-0.8525));
dSX[356]=(float)(kx+l*0.29138); dSY[356]=(float)(ky+l*(1.0-0.73165));
dSX[357]=(float)(kx+l*0.15562); dSY[357]=(float)(ky+l*(1.0-0.80957));
dSX[358]=(float)(kx+l*0.45633); dSY[358]=(float)(ky+l*(1.0-0.62115));
dSX[359]=(float)(kx+l*0.22247); dSY[359]=(float)(ky+l*(1.0-0.73574));
dSX[360]=(float)(kx+l*0.20278); dSY[360]=(float)(ky+l*(1.0-0.02718));
dSX[361]=(float)(kx+l*0.1757); dSY[361]=(float)(ky+l*(1.0-0.77329));
dSX[362]=(float)(kx+l*0.81154); dSY[362]=(float)(ky+l*(1.0-0.34851));
dSX[363]=(float)(kx+l*0.63127); dSY[363]=(float)(ky+l*(1.0-0.19212));
dSX[364]=(float)(kx+l*0.80712); dSY[364]=(float)(ky+l*(1.0-0.3727));
dSX[365]=(float)(kx+l*0.79678); dSY[365]=(float)(ky+l*(1.0-0.37069));
dSX[366]=(float)(kx+l*0.65493); dSY[366]=(float)(ky+l*(1.0-0.17201));
dSX[367]=(float)(kx+l*0.11119); dSY[367]=(float)(ky+l*(1.0-0.55032));
dSX[368]=(float)(kx+l*0.35914); dSY[368]=(float)(ky+l*(1.0-0.69928));
dSX[369]=(float)(kx+l*0.84783); dSY[369]=(float)(ky+l*(1.0-0.38467));
dSX[370]=(float)(kx+l*0.25637); dSY[370]=(float)(ky+l*(1.0-0.16449));
dSX[371]=(float)(kx+l*0.4251); dSY[371]=(float)(ky+l*(1.0-0.75901));
dSX[372]=(float)(kx+l*0.19824); dSY[372]=(float)(ky+l*(1.0-0.85476));
dSX[373]=(float)(kx+l*0.49887); dSY[373]=(float)(ky+l*(1.0-0.69768));
dSX[374]=(float)(kx+l*0.86102); dSY[374]=(float)(ky+l*(1.0-0.37142));
dSX[375]=(float)(kx+l*0.19372); dSY[375]=(float)(ky+l*(1.0-0.80485));
dSX[376]=(float)(kx+l*0.11601); dSY[376]=(float)(ky+l*(1.0-0.55327));
dSX[377]=(float)(kx+l*0.72774); dSY[377]=(float)(ky+l*(1.0-0.87631));
dSX[378]=(float)(kx+l*0.24923); dSY[378]=(float)(ky+l*(1.0-0.79912));
dSX[379]=(float)(kx+l*0.4765); dSY[379]=(float)(ky+l*(1.0-0.68893));
dSX[380]=(float)(kx+l*0.82476); dSY[380]=(float)(ky+l*(1.0-0.35662));
dSX[381]=(float)(kx+l*0.73111); dSY[381]=(float)(ky+l*(1.0-0.17849));
dSX[382]=(float)(kx+l*0.23645); dSY[382]=(float)(ky+l*(1.0-0.8192));
dSX[383]=(float)(kx+l*0.24282); dSY[383]=(float)(ky+l*(1.0-0.79375));
dSX[384]=(float)(kx+l*0.32193); dSY[384]=(float)(ky+l*(1.0-0.73014));
dSX[385]=(float)(kx+l*0.18991); dSY[385]=(float)(ky+l*(1.0-0.76666));
dSX[386]=(float)(kx+l*0.4943); dSY[386]=(float)(ky+l*(1.0-0.64545));
dSX[387]=(float)(kx+l*0.45752); dSY[387]=(float)(ky+l*(1.0-0.68871));
dSX[388]=(float)(kx+l*0.27258); dSY[388]=(float)(ky+l*(1.0-0.75787));
dSX[389]=(float)(kx+l*0.48832); dSY[389]=(float)(ky+l*(1.0-0.66738));
dSX[390]=(float)(kx+l*0.70802); dSY[390]=(float)(ky+l*(1.0-0.84396));
dSX[391]=(float)(kx+l*0.36794); dSY[391]=(float)(ky+l*(1.0-0.63548));
dSX[392]=(float)(kx+l*0.37738); dSY[392]=(float)(ky+l*(1.0-0.73531));
dSX[393]=(float)(kx+l*0.23611); dSY[393]=(float)(ky+l*(1.0-0.10068));
dSX[394]=(float)(kx+l*0.2211); dSY[394]=(float)(ky+l*(1.0-0.77825));
dSX[395]=(float)(kx+l*0.21163); dSY[395]=(float)(ky+l*(1.0-0.12681));
dSX[396]=(float)(kx+l*0.18089); dSY[396]=(float)(ky+l*(1.0-0.73562));
dSX[397]=(float)(kx+l*0.66299); dSY[397]=(float)(ky+l*(1.0-0.22315));
dSX[398]=(float)(kx+l*0.21315); dSY[398]=(float)(ky+l*(1.0-0.13477));
dSX[399]=(float)(kx+l*0.71559); dSY[399]=(float)(ky+l*(1.0-0.89859));
dSX[400]=(float)(kx+l*0.43222); dSY[400]=(float)(ky+l*(1.0-0.77103));
dSX[401]=(float)(kx+l*0.87618); dSY[401]=(float)(ky+l*(1.0-0.37878));
dSX[402]=(float)(kx+l*0.26296); dSY[402]=(float)(ky+l*(1.0-0.15748));
dSX[403]=(float)(kx+l*0.1686); dSY[403]=(float)(ky+l*(1.0-0.20094));
dSX[404]=(float)(kx+l*0.6815); dSY[404]=(float)(ky+l*(1.0-0.10764));
dSX[405]=(float)(kx+l*0.37811); dSY[405]=(float)(ky+l*(1.0-0.70541));
dSX[406]=(float)(kx+l*0.36094); dSY[406]=(float)(ky+l*(1.0-0.67579));
dSX[407]=(float)(kx+l*0.82511); dSY[407]=(float)(ky+l*(1.0-0.41853));
dSX[408]=(float)(kx+l*0.14138); dSY[408]=(float)(ky+l*(1.0-0.23299));
dSX[409]=(float)(kx+l*0.67249); dSY[409]=(float)(ky+l*(1.0-0.20002));
dSX[410]=(float)(kx+l*0.23894); dSY[410]=(float)(ky+l*(1.0-0.17142));
dSX[411]=(float)(kx+l*0.75744); dSY[411]=(float)(ky+l*(1.0-0.14058));
dSX[412]=(float)(kx+l*0.17161); dSY[412]=(float)(ky+l*(1.0-0.10035));
dSX[413]=(float)(kx+l*0.48828); dSY[413]=(float)(ky+l*(1.0-0.66026));
dSX[414]=(float)(kx+l*0.09221); dSY[414]=(float)(ky+l*(1.0-0.24637));
dSX[415]=(float)(kx+l*0.16063); dSY[415]=(float)(ky+l*(1.0-0.59428));
dSX[416]=(float)(kx+l*0.12893); dSY[416]=(float)(ky+l*(1.0-0.59674));
dSX[417]=(float)(kx+l*0.35694); dSY[417]=(float)(ky+l*(1.0-0.78796));
dSX[418]=(float)(kx+l*0.41546); dSY[418]=(float)(ky+l*(1.0-0.76092));
dSX[419]=(float)(kx+l*0.16968); dSY[419]=(float)(ky+l*(1.0-0.83991));
dSX[420]=(float)(kx+l*0.10334); dSY[420]=(float)(ky+l*(1.0-0.13985));
dSX[421]=(float)(kx+l*0.16873); dSY[421]=(float)(ky+l*(1.0-0.03174));
dSX[422]=(float)(kx+l*0.09976); dSY[422]=(float)(ky+l*(1.0-0.57833));
dSX[423]=(float)(kx+l*0.73443); dSY[423]=(float)(ky+l*(1.0-0.86841));
dSX[424]=(float)(kx+l*0.2138); dSY[424]=(float)(ky+l*(1.0-0.14457));
dSX[425]=(float)(kx+l*0.18475); dSY[425]=(float)(ky+l*(1.0-0.73202));
dSX[426]=(float)(kx+l*0.48298); dSY[426]=(float)(ky+l*(1.0-0.70441));
dSX[427]=(float)(kx+l*0.18751); dSY[427]=(float)(ky+l*(1.0-0.17179));
dSX[428]=(float)(kx+l*0.15242); dSY[428]=(float)(ky+l*(1.0-0.56863));
dSX[429]=(float)(kx+l*0.47199); dSY[429]=(float)(ky+l*(1.0-0.60514));
dSX[430]=(float)(kx+l*0.08912); dSY[430]=(float)(ky+l*(1.0-0.59353));
dSX[431]=(float)(kx+l*0.14872); dSY[431]=(float)(ky+l*(1.0-0.63872));
dSX[432]=(float)(kx+l*0.79864); dSY[432]=(float)(ky+l*(1.0-0.35493));
dSX[433]=(float)(kx+l*0.35112); dSY[433]=(float)(ky+l*(1.0-0.78383));
dSX[434]=(float)(kx+l*0.69891); dSY[434]=(float)(ky+l*(1.0-0.84894));
dSX[435]=(float)(kx+l*0.80731); dSY[435]=(float)(ky+l*(1.0-0.39325));
dSX[436]=(float)(kx+l*0.82968); dSY[436]=(float)(ky+l*(1.0-0.3552));
dSX[437]=(float)(kx+l*0.72571); dSY[437]=(float)(ky+l*(1.0-0.19687));
dSX[438]=(float)(kx+l*0.69843); dSY[438]=(float)(ky+l*(1.0-0.84846));
dSX[439]=(float)(kx+l*0.84693); dSY[439]=(float)(ky+l*(1.0-0.40964));
dSX[440]=(float)(kx+l*0.20669); dSY[440]=(float)(ky+l*(1.0-0.77071));
dSX[441]=(float)(kx+l*0.12141); dSY[441]=(float)(ky+l*(1.0-0.58855));
dSX[442]=(float)(kx+l*0.2279); dSY[442]=(float)(ky+l*(1.0-0.12276));
dSX[443]=(float)(kx+l*0.83297); dSY[443]=(float)(ky+l*(1.0-0.39735));
dSX[444]=(float)(kx+l*0.14542); dSY[444]=(float)(ky+l*(1.0-0.56013));
dSX[445]=(float)(kx+l*0.12433); dSY[445]=(float)(ky+l*(1.0-0.20911));
dSX[446]=(float)(kx+l*0.72573); dSY[446]=(float)(ky+l*(1.0-0.8408));
dSX[447]=(float)(kx+l*0.09379); dSY[447]=(float)(ky+l*(1.0-0.55713));
dSX[448]=(float)(kx+l*0.14829); dSY[448]=(float)(ky+l*(1.0-0.23154));
dSX[449]=(float)(kx+l*0.4523); dSY[449]=(float)(ky+l*(1.0-0.67249));
dSX[450]=(float)(kx+l*0.11726); dSY[450]=(float)(ky+l*(1.0-0.19693));
dSX[451]=(float)(kx+l*0.11815); dSY[451]=(float)(ky+l*(1.0-0.25814));
dSX[452]=(float)(kx+l*0.67506); dSY[452]=(float)(ky+l*(1.0-0.17122));
dSX[453]=(float)(kx+l*0.83483); dSY[453]=(float)(ky+l*(1.0-0.40775));
dSX[454]=(float)(kx+l*0.07239); dSY[454]=(float)(ky+l*(1.0-0.18731));
dSX[455]=(float)(kx+l*0.3272); dSY[455]=(float)(ky+l*(1.0-0.7225));
dSX[456]=(float)(kx+l*0.16136); dSY[456]=(float)(ky+l*(1.0-0.61121));
dSX[457]=(float)(kx+l*0.21065); dSY[457]=(float)(ky+l*(1.0-0.13483));
dSX[458]=(float)(kx+l*0.71889); dSY[458]=(float)(ky+l*(1.0-0.20099));
dSX[459]=(float)(kx+l*0.36902); dSY[459]=(float)(ky+l*(1.0-0.7864));
dSX[460]=(float)(kx+l*0.84165); dSY[460]=(float)(ky+l*(1.0-0.36644));
dSX[461]=(float)(kx+l*0.68612); dSY[461]=(float)(ky+l*(1.0-0.12094));
dSX[462]=(float)(kx+l*0.22926); dSY[462]=(float)(ky+l*(1.0-0.16182));
dSX[463]=(float)(kx+l*0.18717); dSY[463]=(float)(ky+l*(1.0-0.11579));
dSX[464]=(float)(kx+l*0.80286); dSY[464]=(float)(ky+l*(1.0-0.32103));
dSX[465]=(float)(kx+l*0.25034); dSY[465]=(float)(ky+l*(1.0-0.04969));
dSX[466]=(float)(kx+l*0.25102); dSY[466]=(float)(ky+l*(1.0-0.81178));
dSX[467]=(float)(kx+l*0.40104); dSY[467]=(float)(ky+l*(1.0-0.70706));
dSX[468]=(float)(kx+l*0.47589); dSY[468]=(float)(ky+l*(1.0-0.62965));
dSX[469]=(float)(kx+l*0.4878); dSY[469]=(float)(ky+l*(1.0-0.77431));
dSX[470]=(float)(kx+l*0.44168); dSY[470]=(float)(ky+l*(1.0-0.69073));
dSX[471]=(float)(kx+l*0.10281); dSY[471]=(float)(ky+l*(1.0-0.2403));
dSX[472]=(float)(kx+l*0.82296); dSY[472]=(float)(ky+l*(1.0-0.3797));
dSX[473]=(float)(kx+l*0.48731); dSY[473]=(float)(ky+l*(1.0-0.69098));
dSX[474]=(float)(kx+l*0.63263); dSY[474]=(float)(ky+l*(1.0-0.22947));
dSX[475]=(float)(kx+l*0.67528); dSY[475]=(float)(ky+l*(1.0-0.20604));
dSX[476]=(float)(kx+l*0.19472); dSY[476]=(float)(ky+l*(1.0-0.11076));
dSX[477]=(float)(kx+l*0.84223); dSY[477]=(float)(ky+l*(1.0-0.34943));
dSX[478]=(float)(kx+l*0.66502); dSY[478]=(float)(ky+l*(1.0-0.2078));
dSX[479]=(float)(kx+l*0.5253); dSY[479]=(float)(ky+l*(1.0-0.70939));
dSX[480]=(float)(kx+l*0.26947); dSY[480]=(float)(ky+l*(1.0-0.10746));
dSX[481]=(float)(kx+l*0.22708); dSY[481]=(float)(ky+l*(1.0-0.7998));
dSX[482]=(float)(kx+l*0.39279); dSY[482]=(float)(ky+l*(1.0-0.6481));
dSX[483]=(float)(kx+l*0.36533); dSY[483]=(float)(ky+l*(1.0-0.74434));
dSX[484]=(float)(kx+l*0.21924); dSY[484]=(float)(ky+l*(1.0-0.76278));
dSX[485]=(float)(kx+l*0.17686); dSY[485]=(float)(ky+l*(1.0-0.18335));
dSX[486]=(float)(kx+l*0.51587); dSY[486]=(float)(ky+l*(1.0-0.5951));
dSX[487]=(float)(kx+l*0.8566); dSY[487]=(float)(ky+l*(1.0-0.40405));
dSX[488]=(float)(kx+l*0.12652); dSY[488]=(float)(ky+l*(1.0-0.57607));
dSX[489]=(float)(kx+l*0.22685); dSY[489]=(float)(ky+l*(1.0-0.79786));
dSX[490]=(float)(kx+l*0.68578); dSY[490]=(float)(ky+l*(1.0-0.8548));
dSX[491]=(float)(kx+l*0.38968); dSY[491]=(float)(ky+l*(1.0-0.73713));
dSX[492]=(float)(kx+l*0.70811); dSY[492]=(float)(ky+l*(1.0-0.19062));
dSX[493]=(float)(kx+l*0.46795); dSY[493]=(float)(ky+l*(1.0-0.68742));
dSX[494]=(float)(kx+l*0.70386); dSY[494]=(float)(ky+l*(1.0-0.13081));
dSX[495]=(float)(kx+l*0.12347); dSY[495]=(float)(ky+l*(1.0-0.57067));
dSX[496]=(float)(kx+l*0.07499); dSY[496]=(float)(ky+l*(1.0-0.58753));
dSX[497]=(float)(kx+l*0.26596); dSY[497]=(float)(ky+l*(1.0-0.75632));
dSX[498]=(float)(kx+l*0.2196); dSY[498]=(float)(ky+l*(1.0-0.81844));
dSX[499]=(float)(kx+l*0.22364); dSY[499]=(float)(ky+l*(1.0-0.11876));
for (int i = 0; i < discreteSize;i++) {
discreteSignalsX[i]=dSX[i];
discreteSignalsY[i]=dSY[i];
}
}
}
protected Point2D.Double circlePoint() {
Point2D.Double origin = new Point2D.Double(0,0);
Point2D.Double signal = new Point2D.Double(0,0);
do {
signal.x = random()-0.5;
signal.y = random()-0.5;
} while (origin.distanceSq(signal) > 0.25 );
// assertion: signal is on circle around origin with diameter 1, radius 0.5
//System.out.printf("%f %f \n",signal.getX(),signal.getY());
return signal;
}
/**
* Generate a signal for the given distribution.
* The result goes into the global variables SignalX
* and SignalY .
*
* @param pd The specified distribution
*/
protected void getSignal(PD pd) {
pd.getSignal(this);
}
/**
* Build a minimum-heap.
*
* @param i The start of the interval
* @param k The end of the interval
*/
protected void buildMinimumHeap(int i, int k) {
int j = i;
int son;
while (2*j <= k) {
if (2*j+1 <= k)
if (nodes[sNodes[2*j]].sqrDist < nodes[sNodes[2*j+1]].sqrDist)
son = 2*j;
else
son = 2*j + 1;
else
son = 2*j;
if (nodes[sNodes[j]].sqrDist > nodes[sNodes[son]].sqrDist) {
int exchange = sNodes[j];
sNodes[j] = sNodes[son];
sNodes[son] = exchange;
j = son;
} else
return;
}
}
public static class Result {
public boolean repaint = false;
public boolean stop = false;
public void reset() {
repaint = false;
stop = false;
}
}
/**
* Do the learning. An input signal is generated for the given distribution
* and forwarded to the switched algorithm.
* Available Algorithms (abbrev):
* Growing Neural Gas (GNG),
* Growing Neural Gas w. Utility (GNG-U),
* Hard Competitive Learning (HCL),
* Neural Gas (NG),
* Neural Gas with Competitive Hebbian Learning (NGwCHL) and
* Competitive Hebbian Learning (CHL).
* LBG (LBG).
* LBG with Utility (LBG-U).
* Growing Grid (GG).
* Self-Organizing Map (SOM).
*
*/
public void learn(Result result) {
result.reset();
//
// learning is done for stepSize steps
//
// Dimension d = getSize();
int curr1stIdx, curr2ndIdx;
int i, j, k, l, m;
int x, y;
int numError, minUtilityNode;
int numNb;
int toDelete;
float dx, dy;
float dstSgmExp;
float bestSqrDist, nextBestDist;
float h_l = 0.0f;
float l_t = 0.0f;
float maxError, minUtility;
NodeGNG curr1st, curr2nd, n_i, node;
SignalX = panelWidth/2; // d.width/2;
SignalY = panelHeight/2; // d.height/2;
valueGraph = 0.0f;
// if (stopB)
// return;
// do stepSize adaption steps using random numSignals
for (k = 0; k < stepSize; k++) {
numSignals++;
if (!algorithm.isDiscrete()) { // neither LBG nor LBG-U
//
// generate random signal and determine winner etc.
//
curr1stIdx = 0;
curr2ndIdx = 0;
curr1st = nodes[curr1stIdx];
curr2nd = nodes[curr2ndIdx];
numError = 0;
minUtilityNode = 0;
maxError = 0.0f;
minUtility = Float.MAX_VALUE;
bestSqrDist = Float.MAX_VALUE;
nextBestDist = Float.MAX_VALUE;
toDelete = -1;
// Get a random signal out of the selected distribution
getSignal(pd);
// Save the numSignals
lastSignalsX[k] = SignalX;
lastSignalsY[k] = SignalY;
// Locate the nearest node (winner) and the second-nearest (runner-up)
for (i = 0 ; i < nNodes ; i++) {
n_i = nodes[i];
n_i.isWinner = n_i.isSecond = n_i.hasMoved = false;
if ((algorithm.isGNGType()) && (!noNewNodesGNGB) && ((numSignals % lambdaGNG) == 0))
n_i.isMostRecentlyInserted = false;
// Mark node without neighbors (one each run is enough)
if (n_i.numNeighbors() == 0)
toDelete = i;
// Calculate squared distance to input signal
n_i.sqrDist =
(n_i.x - SignalX) * (n_i.x - SignalX) +
(n_i.y - SignalY) * (n_i.y - SignalY);
// Decay error and utility
n_i.error *= decayFactor;
n_i.utility *= decayFactorUtility;
n_i.tau *= decayFactor;
// Keep track of current first and second winner
if (n_i.sqrDist <= bestSqrDist) { // changed to <= to handle strange cases with all nodes in one position
curr2nd = curr1st;
curr2ndIdx = curr1stIdx;
curr1st = n_i;
curr1stIdx = i;
nextBestDist = bestSqrDist;
bestSqrDist = n_i.sqrDist;
}
// Calculate node with maximal Error
if (n_i.error > maxError) {
maxError = n_i.error;
numError = i;
}
// Calculate node with minimum utility (GNG-U)
if (n_i.utility < minUtility) {
minUtility = n_i.utility;
minUtilityNode = i;
}
}
//
// assertion: winner should be determined here
//
if (Float.isNaN(curr1st.x)){ // hack
System.out.printf("learn(): Float.isNaN(pick.x) stopping .....\n");
result.stop = true;
// stop();
return;
}
valueGraph += bestSqrDist;
// Mark winner for teach-mode
curr1st.isWinner = true;
curr1st.x_old = curr1st.x;
curr1st.y_old = curr1st.y;
//System.out.printf("learn(): x_grid = %d y_grid = %d \n", pick.x_grid, pick.x_grid); //hack bf
// Adapt nodes
// Trial: only adapt if signal is closer than delta
//if (bestDist>400){
// break;
//}
//
// do adaptation ("learning") according to current model
//
switch (algorithm) {
//
// Growing Neural Gas
//
case GNGU: //does not occur, since it is mapped to GNG
case GNG:
// Find second-closest node (continued)
if (curr1stIdx == curr2ndIdx) {
curr2ndIdx++;
nextBestDist = Float.MAX_VALUE;
curr2nd = nodes[curr2ndIdx];
}
for (i = curr1stIdx + 1 ; i < nNodes ; i++) {
//n_i = nodes[i];
if (nodes[i].sqrDist < nextBestDist) {
curr2nd = nodes[i];
curr2ndIdx = i;
nextBestDist = nodes[i].sqrDist;
}
}
// Mark second for teach-mode
curr2nd.isSecond = true;
curr2nd.x_old = curr2nd.x;
curr2nd.y_old = curr2nd.y;
// Adaptation of Winner:
dx = epsilonGNG * (SignalX - curr1st.x);
dy = epsilonGNG * (SignalY - curr1st.y);
curr1st.adapt(dx,dy);
numNb = curr1st.numNeighbors();
// Adaptation of Neighbors:
int nn;
for (i = 0; i < numNb; i++) {
nn = curr1st.neighbor(i);
nodes[nn].hasMoved = true;
curr2nd.x_old = curr2nd.x;
curr2nd.y_old = curr2nd.y;
dx = epsilonGNG2 * (SignalX - nodes[nn].x);
dy = epsilonGNG2 * (SignalY - nodes[nn].y);
nodes[nn].adapt(dx,dy);
}
// Accumulate square error
curr1st.error += bestSqrDist;
// Accumulate utility
curr1st.utility += (nextBestDist - bestSqrDist);
// Connect the two winning nodes
addEdge(curr1stIdx, curr2ndIdx);
// Calculate the age of the connected edges and delete too old edges
ageEdgesOfNode(curr1stIdx);
// Check inserting node and insert if necessary
if ( (numSignals % lambdaGNG) == 0 ) {
if (!noNewNodesGNGB) {
if (autoStopB) {
if (nNodes >= maxNodes || (GNG_U_B && (numSignals > 300000))) {
result.stop = true;
break;
}
}
final int nodeIdx = insertNode(numError, maximumErrorNeighbor(numError));
// result.insertedSound = nodeIdx != -1;
}
}
// Delete Node without Neighbors (not GNG-U)
if ((toDelete != -1) && (nNodes > 2) && !GNG_U_B )
deleteNode(toDelete);
// Delete Node with very low utility
else {
if ( maxError > minUtility * utilityGNG) {
if (GNG_U_B && (nNodes > 2)) {
deleteNode(minUtilityNode);
}
} else if ( (nNodes > 2) && (nNodes > maxNodes) ) {
// relevant if maxnodes is lowered during the simulation
deleteNode(minUtilityNode);
}
}
break;
//
// Hard Competitive Learning
//
case HCL:
if ((numSignals >= t_max) && (variableB || autoStopB)) {
result.repaint = true;
result.stop = true;
break;
}
// Adapt picked node
if (variableB) {
e_t = (float)(e_i * Math.pow(e_f/e_i, numSignals /t_max));
dx = e_t * (SignalX - curr1st.x);
dy = e_t * (SignalY - curr1st.y);
curr1st.adapt(dx,dy);
} else {
dx = epsilon * (SignalX - curr1st.x);
dy = epsilon * (SignalY - curr1st.y);
curr1st.adapt(dx,dy);
}
break;
//
// Neural Gas
//
case NG:
if (numSignals >= t_max) {
result.repaint = true;
result.stop = true;
break;
}
// Initialize the sorted node array, if necessary
if (nNodesChangedB) {
for (i = 1; i <= nNodes; i++)
sNodes[i] = i-1;
nNodesChangedB = false;
}
l_t = (float)(l_i * Math.pow(l_f/l_i, numSignals /t_max));
e_t = (float)(e_i * Math.pow(e_f/e_i, numSignals /t_max));
// Build a minimum heap
for (i = nNodes/2; i > 0; i--)
buildMinimumHeap(i, nNodes);
{
int decrNnodes = nNodes - 1;
int minimum;
// Fetch minimum, calculate new position and reheap
for (i = nNodes; i > 0; i--) {
minimum = sNodes[1];
sNodes[1] = sNodes[i];
sNodes[i] = minimum;
n_i = nodes[minimum];
// Mark second for teach-mode
if (i == decrNnodes)
nodes[minimum].isSecond = true;
h_l = (float)(Math.exp(-(nNodes - i)/l_t));
// Adapt nodes
dx = e_t * h_l * (SignalX - n_i.x);
dy = e_t * h_l * (SignalY - n_i.y);
n_i.adapt(dx, dy);
if ( (Math.abs(dx) < 1.0) &&
(Math.abs(dy) < 1.0) &&
(i < decrNnodes) )
break;
buildMinimumHeap(1, i-1);
}
}
break;
//
// Neural Gas with Competitive Hebbian Learning
//
case NGCHL:
if (numSignals >= t_max) {
result.repaint = true;
result.stop = true;
break;
}
// Initialize the sorted node array, if necessary
if (nNodesChangedB) {
for (i = 1; i <= nNodes; i++)
sNodes[i] = i-1;
nNodesChangedB = false;
}
l_t = (float)(l_i * Math.pow(l_f/l_i, numSignals /t_max));
e_t = (float)(e_i * Math.pow(e_f/e_i, numSignals /t_max));
// Calculate the new edge-deleting term
maxEdgeAge = (int) (delEdge_i *
Math.pow(delEdge_f/delEdge_i, numSignals /t_max));
// Build a minimum heap
for (i = nNodes/2; i > 0; i--)
buildMinimumHeap(i, nNodes);
{
int decrNnodes = nNodes - 1;
int minimum;
// Fetch minimum, calculate new position and reheap
for (i = nNodes; i > 0; i--) {
minimum = sNodes[1];
sNodes[1] = sNodes[i];
sNodes[i] = minimum;
n_i = nodes[minimum];
// Mark second for teach-mode
if (i == decrNnodes) {
nodes[minimum].isSecond = true;
// This is the only difference between NG and NGwCHL:
// - Connect the first and the second node
addEdge(sNodes[nNodes], sNodes[nNodes - 1]);
// - Calculate the age of the connected edges and
// delete too old edges
ageEdgesOfNode(sNodes[nNodes]);
}
h_l = (float)(Math.exp(-(nNodes - i)/l_t));
// Adapt nodes
dx = e_t * h_l * (SignalX - n_i.x);
dy = e_t * h_l * (SignalY - n_i.y);
n_i.adapt(dx, dy);
if ( (Math.abs(dx) < 1.0) &&
(Math.abs(dy) < 1.0) &&
(i < decrNnodes) )
break;
buildMinimumHeap(1, i-1);
}
}
break;
//
// Competitive Hebbian Learning
//
case CHL:
if ((numSignals >= 50000) && autoStopB) {
result.repaint = true;
result.stop = true;
break;
}
// Find second node (continued)
if (curr1stIdx == curr2ndIdx) {
curr2ndIdx++;
nextBestDist = Float.MAX_VALUE;
curr2nd = nodes[curr2ndIdx];
}
for (i = curr1stIdx + 1 ; i < nNodes ; i++) {
n_i = nodes[i];
if (n_i.sqrDist < nextBestDist) {
curr2nd = n_i;
curr2ndIdx = i;
nextBestDist = n_i.sqrDist;
}
}
// Mark second for teach-mode
curr2nd.isSecond = true;
curr2nd.x_old = curr2nd.x;
curr2nd.y_old = curr2nd.y;
// Connect the nodes
addEdge(curr1stIdx, curr2ndIdx);
break;
//
// Growing Grid
//
case GG:
case GR:
x = curr1st.x_grid;
y = curr1st.y_grid;
if ((x < 0)||(y<0)){
System.out.printf("learn(): Disaster, x_grid or y_grid < 0, x=%d, y=%d, pick.x = %f pick.y = %f continuing not! .....\n",x,y,curr1st.x, curr1st.y);
result.stop = true;
break;
}
// count numSignals (leads to density estimation by node density)
grid[x][y].node.tau+=1.0;
if (fineTuningB) {
int percent;
// tMax proportional to network size
float tMax = gridWidth * gridHeight * l_f;
if (algorithm.equals(Algorithm.GR)) {
tMax = gridWidth * gridHeight * 10;
}
e_t = (float)(e_i * Math.pow(e_f/e_i, (numSignals - numSignalsTmp)/tMax));
percent = (int) (((numSignals - numSignalsTmp)*100)/tMax);
if (percent >= 100) {
fineTuningS = "Fine-tuning (100%)";
log("fine tuning at 100%, calling stop ....");
result.repaint = true;
result.stop = true; // stop after fine-tuning
break;
}
fineTuningS = "Fine-tuning (" + String.valueOf(percent) + "%)";
} else {
e_t = e_i;
}
int dist;
for (i = 0; i < gridWidth; i++) {
for (j = 0; j < gridHeight; j++) {
if (torusGGB) {
// Manhattan Torus Distance
float xxx = Math.min(Math.abs(x-i), Math.min(x+Math.abs(gridWidth-1-i),i+Math.abs(gridWidth-1-x)));
dist = (int) xxx + Math.abs(y - j);
} else {
// Manhattan Distance
dist = Math.abs(x - i) + Math.abs(y - j);
}
node = grid[i][j].node;
dstSgmExp = (float) (Math.exp(-(dist*dist)/(2.0 * sigma * sigma)));
dx = e_t * dstSgmExp * (SignalX - node.x);
dy = e_t * dstSgmExp * (SignalY - node.y);
node.adapt(dx, dy);
if ( dstSgmExp > 0.5f )
node.isSecond = true;
}
}
// Check inserting nodes and insert if necessary
if ( (numSignals % (gridWidth * gridHeight * l_i) == 0) && (!fineTuningB) ) {
if (!noNewNodesGGB) {
if(enlargeGrid()) {
// result.insertedSound = true;
fineTuningB = false;
} else {
// result.insertedSound = false;
fineTuningB = true;
log("fine-tuning .....");
}
numSignalsTmp = numSignals;
// if (inserted) {
// break;
// }
}
}
break;
//
// Self-Organizing Map
//
case SOM:
if (numSignals >= t_max){
result.stop = true; // stop adaptation
break;
}
// Adapt nodes
x = curr1st.x_grid;
y = curr1st.y_grid;
e_t = (float)(e_i * Math.pow(e_f/e_i, numSignals /t_max));
sigma = (float)(sigma_i * Math.pow(sigma_f, numSignals /t_max));
for (i = 0; i < gridWidth; i++) {
for (j = 0; j < gridHeight; j++) {
// Distance
if (torusSOMB) {
// Manhattan Torus Distance
float xxx = Math.min(Math.abs(x-i), Math.min(x+Math.abs(gridWidth-1-i),i+Math.abs(gridWidth-1-x)));
dist = (int) xxx + Math.abs(y - j);
} else {
// Manhattan Distance
dist = Math.abs(x - i) + Math.abs(y - j);
}
node = grid[i][j].node;
dstSgmExp = (float) (Math.exp(-(dist*dist)/(2.0 * sigma * sigma)));
dx = e_t * dstSgmExp * (SignalX - node.x);
dy = e_t * dstSgmExp * (SignalY - node.y);
node.adapt(dx, dy);
if ( dstSgmExp > 0.5f )
node.isSecond = true;
}
}
break;
case LBG:
case LBGU:
// can not happen since in this branch only non-discrete distributions
// are handled
break;
} // switch
} else
{
//
// discrete algorithm (LBG/LBG-U)
//
readyLBG_B = true;
int noOfSignals, sig;
int wa = 0, wb = 0;
float bestDistLBG, nextBestDistLBG;
float utility = 0.0f;
float minUtilityLBG = Float.MAX_VALUE;
float error = 0.0f;
float maxErrorLBG = 0.0f;
float errorAct = 0.0f;
FPoint tmpFP;
curr1stIdx = 0;
// loop over finite set of input numSignals
for (j = 0; j < numDiscreteSignals; j++) {
curr1st = nodes[0];
curr2nd = nodes[0];
bestDistLBG = Float.MAX_VALUE;
nextBestDistLBG = Float.MAX_VALUE;
// Locate the nearest node and prepare for the second
for (i = 0; i < nNodes; i++) {
n_i = nodes[i];
// Calculate distance
n_i.sqrDist = (n_i.x - discreteSignalsX[j]) *
(n_i.x - discreteSignalsX[j]) +
(n_i.y - discreteSignalsY[j]) *
(n_i.y - discreteSignalsY[j]);
// Calculate node with best distance and prepare for second
if (n_i.sqrDist < bestDistLBG) {
curr2nd = curr1st;
curr1stIdx = i;
curr1st = n_i;
nextBestDistLBG = bestDistLBG;
bestDistLBG = n_i.sqrDist;
}
}
// Store distance to the nearest codebook vector (LBG-U)
discreteSignalsD1[j] = bestDistLBG;
errorAct += bestDistLBG;
// Add signal index to the winning codebook vector
curr1st.addSignal(j);
// Find node with second best distance
if (curr1st == curr2nd)
nextBestDistLBG = Float.MAX_VALUE;
for (i = curr1stIdx + 1; i < nNodes; i++) {
n_i = nodes[i];
if (n_i.sqrDist < nextBestDistLBG) {
curr2nd = n_i;
nextBestDistLBG = n_i.sqrDist;
}
}
// Store distance to the second nearest codebook vector (LBG-U)
discreteSignalsD2[j] = nextBestDistLBG;
valueGraph += bestDistLBG;
}
minUtilityLBG = Float.MAX_VALUE;
maxErrorLBG = 0.0f;
// Adapt selected nodes
for (l = 0; l < nNodes; l++) {
n_i = nodes[l];
tmpFP = new FPoint(n_i.x, n_i.y);
utility = 0.0f;
error = 0.0f;
noOfSignals = n_i.numSignals();
if (noOfSignals > 0) {
for (m = 0; m < noOfSignals; m++) {
sig = n_i.removeSignal();
dx = discreteSignalsX[sig];
dy = discreteSignalsY[sig];
n_i.adapt(dx, dy);
// calculate utility
utility += (discreteSignalsD2[sig] -
discreteSignalsD1[sig]);
// calculate error
error += discreteSignalsD1[sig];
}
n_i.x /= (noOfSignals + 1.0f);
n_i.y /= (noOfSignals + 1.0f);
// nodes moved?
if (!tmpFP.equal(n_i.x, n_i.y)) {
n_i.hasMoved = true;
readyLBG_B = false;
} else {
n_i.hasMoved = false;
}
// determine minimum utility
if (utility < minUtilityLBG) {
wa = l;
minUtilityLBG = utility;
}
// determine maximum error
if (error > maxErrorLBG) {
wb = l;
maxErrorLBG = error;
}
}
}
if (LBG_U_B) {
if (DEBUG)
log("Act: " + errorAct
+ ", Best: " + errorBestLBG_U);
if (readyLBG_B && (errorAct < errorBestLBG_U) ) {
// Save old positions
for (i = 0; i < nNodes; i++) {
C_best[i] = new FPoint(nodes[i].x,
nodes[i].y);
}
readyLBG_B = false;
errorBestLBG_U = errorAct;
// move node from wa to wb with a small offset (LBG-U)
// IMPORTANT: This works only for image data space!!!
dx = nodes[wb].x - nodes[wa].x;
dy = nodes[wb].y + 1 - nodes[wa].y;
nodes[wa].adapt(dx, dy);
//nodes[wa].x = nodes[wb].x;
//nodes[wa].y = nodes[wb].y + 1;
} else if (readyLBG_B && (errorAct > errorBestLBG_U) ) {
// Restore old positions
for (i = 0; i < nNodes; i++) {
nodes[i].x = C_best[i].x;
nodes[i].y = C_best[i].y;
}
}
}
if (readyLBG_B && autoStopB) {
result.repaint = true;
result.stop = true;
}
} // if (algorithm.isDiscrete())
// if (stopB==true)
// break;
} // loop over stepSize
return;
}
/**
* The mouse-selected node.
*/
protected NodeGNG pick;
/**
* The flag for mouse-selected node.
*/
protected boolean pickFixed;
// repaint --> update() ---> paintComponent()
// /**
// * Update the drawing area.
// *
// * @param g The graphic context
// */
// static int paintCounter =0;
// static int prevSigs=0;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy