View Javadoc

1   /*
2   * Copyright (c) 2003, the JUNG Project and the Regents of the University 
3   * of California
4   * All rights reserved.
5   *
6   * This software is open-source under the BSD license; see either
7   * "license.txt" or
8   * http://jung.sourceforge.net/license.txt for a description.
9   */
10  package edu.uci.ics.jung.algorithms.layout3d;
11  
12  import java.util.ArrayList;
13  import java.util.Collection;
14  import java.util.ConcurrentModificationException;
15  import java.util.HashMap;
16  import java.util.List;
17  import java.util.Map;
18  
19  import javax.vecmath.Point3f;
20  import javax.vecmath.Vector3f;
21  
22  import org.apache.commons.collections15.Factory;
23  import org.apache.commons.collections15.map.LazyMap;
24  
25  import edu.uci.ics.jung.algorithms.util.IterativeContext;
26  import edu.uci.ics.jung.graph.Graph;
27  
28  /**
29   * Implements a self-organizing map layout algorithm, based on Meyer's
30   * self-organizing graph methods.
31   * 
32   * @author Yan Biao Boey
33   */
34  public class ISOMLayout<V, E> extends AbstractLayout<V,E> implements IterativeContext {
35  
36  	Map<V, ISOMVertexData> isomVertexData = 
37  		LazyMap.decorate(new HashMap<V, ISOMVertexData>(),
38  				new Factory<ISOMVertexData>() {
39  					public ISOMVertexData create() {
40  						return new ISOMVertexData();
41  					}});
42  
43  	private int maxEpoch;
44  	private int epoch;
45  
46  	private int radiusConstantTime;
47  	private int radius;
48  	private int minRadius;
49  
50  	private double adaption;
51  	private double initialAdaption;
52  	private double minAdaption;
53      
54      protected GraphElementAccessor<V,E> elementAccessor = 
55      	new RadiusGraphElementAccessor<V,E>();
56  
57  	private double coolingFactor;
58  
59  	private List<V> queue = new ArrayList<V>();
60  	private String status = null;
61  	
62  	/**
63  	 * Returns the current number of epochs and execution status, as a string.
64  	 */
65  	public String getStatus() {
66  		return status;
67  	}
68  
69  	public ISOMLayout(Graph<V,E> g) {
70  		super(g);
71  	}
72  
73  	public void initialize() {
74  
75  		setInitializer(new RandomLocationTransformer<V>(getSize()));
76  		maxEpoch = 2000;
77  		epoch = 1;
78  
79  		radiusConstantTime = 100;
80  		radius = 5;
81  		minRadius = 1;
82  
83  		initialAdaption = 90.0D / 100.0D;
84  		adaption = initialAdaption;
85  		minAdaption = 0;
86  
87  		//factor = 0; //Will be set later on
88  		coolingFactor = 2;
89  
90  		//temperature = 0.03;
91  		//initialJumpRadius = 100;
92  		//jumpRadius = initialJumpRadius;
93  
94  		//delay = 100;
95  	}
96  	
97  
98  	/**
99  	* Advances the current positions of the graph elements.
100 	*/
101 	public void step() {
102 		status = "epoch: " + epoch + "; ";
103 		if (epoch < maxEpoch) {
104 			adjust();
105 			updateParameters();
106 			status += " status: running";
107 
108 		} else {
109 			status += "adaption: " + adaption + "; ";
110 			status += "status: done";
111 //			done = true;
112 		}
113 	}
114 
115 	ISOMVertexData tempISOM;
116 	Point3f tempXYD;
117 
118 	private synchronized void adjust() {
119 		//Generate random position in graph space
120 		tempISOM = new ISOMVertexData();
121 		tempXYD = new Point3f();
122 
123 		// creates a new XYZ data location
124         tempXYD.set((float)(10 + Math.random() * getSize().getRadius()),
125                 (float)(10 + Math.random() * getSize().getRadius()),
126                 (float)(10 + Math.random() * getSize().getRadius()));
127 
128 		//Get closest vertex to random position
129 		V winner = elementAccessor.getVertex(this, tempXYD);
130 
131 		while(true) {
132 		    try {
133 		    	for(V v : getGraph().getVertices()) {
134 		            ISOMVertexData ivd = getISOMVertexData(v);
135 		            ivd.distance = 0;
136 		            ivd.visited = false;
137 		        }
138 		        break;
139 		    } catch(ConcurrentModificationException cme) {}
140         }
141 		adjustVertex(winner);
142 	}
143 
144 	private synchronized void updateParameters() {
145 		epoch++;
146 		double factor = Math.exp(-1 * coolingFactor * (1.0 * epoch / maxEpoch));
147 		adaption = Math.max(minAdaption, factor * initialAdaption);
148 		//jumpRadius = (int) factor * jumpRadius;
149 		//temperature = factor * temperature;
150 		if ((radius > minRadius) && (epoch % radiusConstantTime == 0)) {
151 			radius--;
152 		}
153 	}
154 
155 	private synchronized void adjustVertex(V v) {
156 		queue.clear();
157 		ISOMVertexData ivd = getISOMVertexData(v);
158 		ivd.distance = 0;
159 		ivd.visited = true;
160 		queue.add(v);
161 		V current;
162 
163 		while (!queue.isEmpty()) {
164 			current = queue.remove(0);
165 			ISOMVertexData currData = getISOMVertexData(current);
166 			Point3f currXYData = transform(current);
167 
168 			double dx = tempXYD.getX() - currXYData.getX();
169 			double dy = tempXYD.getY() - currXYData.getY();
170 			double dz = tempXYD.getZ() - currXYData.getZ();
171 			double factor = adaption / Math.pow(2, currData.distance);
172 			
173 			currXYData.set((float)(currXYData.getX()+(factor*dx)), 
174 					(float)(currXYData.getY()+(factor*dy)),
175 					(float)(currXYData.getZ()+(factor*dz)));
176 //			currXYData.addX(factor * dx);
177 //			currXYData.addY(factor * dy);
178 
179 			if (currData.distance < radius) {
180 			    Collection<V> s = getGraph().getNeighbors(current);
181 			    	//current.getNeighbors();
182 			    while(true) {
183 			        try {
184 			        	for(V child : s) {
185 //			            for (Iterator iter = s.iterator(); iter.hasNext();) {
186 //			                Vertex child = (Vertex) iter.next();
187 			                ISOMVertexData childData = getISOMVertexData(child);
188 			                if (childData != null && !childData.visited) {
189 			                    childData.visited = true;
190 			                    childData.distance = currData.distance + 1;
191 			                    queue.add(child);
192 			                }
193 			            }
194 			            break;
195 			        } catch(ConcurrentModificationException cme) {}
196 			    }
197 			}
198 		}
199 	}
200 
201 	public ISOMVertexData getISOMVertexData(V v) {
202 		return isomVertexData.get(v);
203 	}
204 
205 	/**
206 	 * This one is an incremental visualization.
207 	 * @return <code>true</code> is the layout algorithm is incremental, <code>false</code> otherwise
208 	 */
209 	public boolean isIncremental() {
210 		return true;
211 	}
212 
213 	/**
214 	 * For now, we pretend it never finishes.
215 	 * @return <code>true</code> is the increments are done, <code>false</code> otherwise
216 	 */
217 	public boolean done() {
218 		return epoch >= maxEpoch;
219 	}
220 
221 	public static class ISOMVertexData {
222 		public Vector3f disp;
223 
224 		int distance;
225 		boolean visited;
226 
227 		public ISOMVertexData() {
228 			initialize();
229 		}
230 
231 		public void initialize() {
232 			disp = new Vector3f();
233 
234 			distance = 0;
235 			visited = false;
236 		}
237 
238 		public double getXDisp() {
239 			return disp.getX();
240 		}
241 
242 		public double getYDisp() {
243 			return disp.getY();
244 		}
245 
246 		public double getZDisp() {
247 			return disp.getZ();
248 		}
249 
250 		public void setDisp(double x, double y, double z) {
251 			disp.set((float)x, (float)y, (float)z);
252 //			disp.set(1, y);
253 		}
254 
255 		public void incrementDisp(double x, double y, double z) {
256 			disp.add(new Vector3f((float)x, (float)y, (float)z));
257 //			disp.set(1, disp.get(1) + y);
258 		}
259 
260 		public void decrementDisp(double x, double y, double z) {
261 			disp.sub(new Vector3f((float)x, (float)y, (float)z));
262 //			disp.set(1, disp.get(1) - y);
263 		}
264 	}
265 
266 	public void reset() {
267 		epoch = 0;
268 	}
269 }