2 * Copyright (c) 2003, the JUNG Project and the Regents of the University
6 * This software is open-source under the BSD license; see either
8 * http://jung.sourceforge.net/license.txt for a description.
10 package edu.uci.ics.jung.algorithms.layout;
12 import edu.uci.ics.jung.algorithms.layout.util.RandomLocationTransformer;
13 import edu.uci.ics.jung.algorithms.util.IterativeContext;
14 import edu.uci.ics.jung.graph.Graph;
16 import org.apache.commons.collections15.Factory;
17 import org.apache.commons.collections15.map.LazyMap;
19 import java.awt.geom.Point2D;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.ConcurrentModificationException;
23 import java.util.HashMap;
24 import java.util.List;
28 * Implements a self-organizing map layout algorithm, based on Meyer's
29 * self-organizing graph methods.
31 * @author Yan Biao Boey
33 public class ISOMLayout<V, E> extends AbstractLayout<V,E> implements IterativeContext {
35 Map<V, ISOMVertexData> isomVertexData =
36 LazyMap.decorate(new HashMap<V, ISOMVertexData>(),
37 new Factory<ISOMVertexData>() {
38 public ISOMVertexData create() {
39 return new ISOMVertexData();
45 private int radiusConstantTime;
47 private int minRadius;
49 private double adaption;
50 private double initialAdaption;
51 private double minAdaption;
53 protected GraphElementAccessor<V,E> elementAccessor =
54 new RadiusGraphElementAccessor<V,E>();
56 private double coolingFactor;
58 private List<V> queue = new ArrayList<V>();
59 private String status = null;
62 * Returns the current number of epochs and execution status, as a string.
64 public String getStatus() {
69 * Creates an <code>ISOMLayout</code> instance for the specified graph <code>g</code>.
72 public ISOMLayout(Graph<V,E> g) {
76 public void initialize() {
78 setInitializer(new RandomLocationTransformer<V>(getSize()));
82 radiusConstantTime = 100;
86 initialAdaption = 90.0D / 100.0D;
87 adaption = initialAdaption;
90 //factor = 0; //Will be set later on
94 //initialJumpRadius = 100;
95 //jumpRadius = initialJumpRadius;
102 * Advances the current positions of the graph elements.
105 status = "epoch: " + epoch + "; ";
106 if (epoch < maxEpoch) {
109 status += " status: running";
112 status += "adaption: " + adaption + "; ";
113 status += "status: done";
118 private synchronized void adjust() {
119 //Generate random position in graph space
120 Point2D tempXYD = new Point2D.Double();
122 // creates a new XY data location
123 tempXYD.setLocation(10 + Math.random() * getSize().getWidth(),
124 10 + Math.random() * getSize().getHeight());
126 //Get closest vertex to random position
127 V winner = elementAccessor.getVertex(this, tempXYD.getX(), tempXYD.getY());
131 for(V v : getGraph().getVertices()) {
132 ISOMVertexData ivd = getISOMVertexData(v);
137 } catch(ConcurrentModificationException cme) {}
139 adjustVertex(winner, tempXYD);
142 private synchronized void updateParameters() {
144 double factor = Math.exp(-1 * coolingFactor * (1.0 * epoch / maxEpoch));
145 adaption = Math.max(minAdaption, factor * initialAdaption);
146 //jumpRadius = (int) factor * jumpRadius;
147 //temperature = factor * temperature;
148 if ((radius > minRadius) && (epoch % radiusConstantTime == 0)) {
153 private synchronized void adjustVertex(V v, Point2D tempXYD) {
155 ISOMVertexData ivd = getISOMVertexData(v);
161 while (!queue.isEmpty()) {
162 current = queue.remove(0);
163 ISOMVertexData currData = getISOMVertexData(current);
164 Point2D currXYData = transform(current);
166 double dx = tempXYD.getX() - currXYData.getX();
167 double dy = tempXYD.getY() - currXYData.getY();
168 double factor = adaption / Math.pow(2, currData.distance);
170 currXYData.setLocation(currXYData.getX()+(factor*dx), currXYData.getY()+(factor*dy));
172 if (currData.distance < radius) {
173 Collection<V> s = getGraph().getNeighbors(current);
177 ISOMVertexData childData = getISOMVertexData(child);
178 if (childData != null && !childData.visited) {
179 childData.visited = true;
180 childData.distance = currData.distance + 1;
185 } catch(ConcurrentModificationException cme) {}
191 protected ISOMVertexData getISOMVertexData(V v) {
192 return isomVertexData.get(v);
196 * This one is an incremental visualization.
197 * @return <code>true</code> is the layout algorithm is incremental, <code>false</code> otherwise
199 public boolean isIncremental() {
204 * Returns <code>true</code> if the vertex positions are no longer being
205 * updated. Currently <code>ISOMLayout</code> stops updating vertex
206 * positions after a certain number of iterations have taken place.
207 * @return <code>true</code> if the vertex position updates have stopped,
208 * <code>false</code> otherwise
210 public boolean done() {
211 return epoch >= maxEpoch;
214 protected static class ISOMVertexData {
218 protected ISOMVertexData() {
225 * Resets the layout iteration count to 0, which allows the layout algorithm to
226 * continue updating vertex positions.
228 public void reset() {