/*
* Copyright 2004-2010 Information & Software Engineering Group (188/1)
* Institute of Software Technology and Interactive Systems
* Vienna University of Technology, Austria
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.ifs.tuwien.ac.at/dm/somtoolbox/license.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package at.tuwien.ifs.somtoolbox.visualization.minimumSpanningTree;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.logging.Logger;
import at.tuwien.ifs.somtoolbox.layers.Unit;
import at.tuwien.ifs.somtoolbox.layers.metrics.L2Metric;
import at.tuwien.ifs.somtoolbox.layers.metrics.MetricException;
import at.tuwien.ifs.somtoolbox.models.GrowingSOM;
/**
* @author Thomas Kern
* @author Magdalena Widl
* @author Rudolf Mayer
* @version $Id: Graph.java 3883 2010-11-02 17:13:23Z frank $
*/
public abstract class Graph {
public static L2Metric metric = new L2Metric();
// / Adjacency List
protected TreeMap<Node, LinkedList<Edge>> adjList;
// A list of the edges in the graph
protected ArrayList<Edge> edges;
protected GrowingSOM gsom;
protected List<Edge> mst;
protected double maximumEdgeWeight;
protected double minimumEdgeWeight;
public Graph(GrowingSOM gsom) {
this.gsom = gsom;
edges = new ArrayList<Edge>();
adjList = new TreeMap<Node, LinkedList<Edge>>();
minimumEdgeWeight = Double.MAX_VALUE;
maximumEdgeWeight = -Double.MAX_VALUE;
}
protected abstract List<Edge> calculateEdge();
protected void connectTwoNodes(Unit unit, HashMap<Unit, Unit> hm, Unit neighbour) {
String lu = unit.toString();
String lv = neighbour.toString();
Node u = getNode(lu);
Node v = getNode(lv);
try {
if (!(hm.containsKey(unit) && hm.get(unit) == neighbour || hm.containsKey(neighbour)
&& hm.get(neighbour) == unit)) {
insert(u, v, metric.distance(unit.getWeightVector(), neighbour.getWeightVector()));
hm.put(unit, neighbour);
}
} catch (MetricException e) {
// does not happen
e.printStackTrace();
Logger.getLogger("at.tuwien.ifs.somtoolbox").severe(e.getMessage());
}
}
protected abstract void createNodes(Unit[] units);
public abstract void drawLine(Graphics2D g, int unitWidth, int unitHeight, Edge e, boolean weighting);
public List<Edge> getMinimumSpanningTree() {
if (mst == null) {
this.mst = this.calculateEdge();
}
return mst;
}
protected abstract ArrayList<Unit> getNeighbours(int horIndex, int verIndex, Unit[][] units);
protected Node getNode(String label) {
for (Node n : adjList.keySet()) {
if (n.getLabel().equals(label)) {
return n;
}
}
return null;
}
protected void insert(Node u, Node v, double w) {
Edge e = new Edge(u, v, w);
adjList.get(u).add(e);
adjList.get(v).add(new Edge(v, u, w));
edges.add(e);
}
protected List<Edge> kruskalMST() {
// Create an empty list of edges to hold the tree edges (for Kruskal)
ArrayList<Edge> treeEdges = new ArrayList<Edge>();
// Create a set for every node
LinkedList<TreeSet<Node>> kruskalSets = new LinkedList<TreeSet<Node>>();
for (Node n : adjList.keySet()) {
TreeSet<Node> s = new TreeSet<Node>();
s.add(n);
kruskalSets.add(s);
}
// Sort edges by weight (Fancy code...)
Collections.sort(edges, new Comparator<Edge>() {
@Override
public int compare(Edge e1, Edge e2) {
return e1.getWeight() > e2.getWeight() ? 1 : -1;
}
});
/* Do Kruskal */
for (Edge e : edges) {
Node u = e.getStart();
Node v = e.getEnd();
TreeSet<Node> uset = null;
TreeSet<Node> vset = null;
for (TreeSet<Node> s : kruskalSets) {
if (s.contains(u)) {
uset = s;
}
if (s.contains(v)) {
vset = s;
}
}
assert uset != null;
if (!uset.equals(vset)) {
uset.addAll(vset);
kruskalSets.remove(vset);
treeEdges.add(e);
}
}
// compute extrema
for (Edge e : treeEdges) {
if (maximumEdgeWeight < e.getWeight()) {
maximumEdgeWeight = e.getWeight();
}
if (minimumEdgeWeight > e.getWeight()) {
minimumEdgeWeight = e.getWeight();
}
}
return treeEdges;
}
protected int[] computeLineThickness(Edge e, int unitWidth, int unitHeight, boolean weighting) {
// draw the line & circle approx. 1/10 of the unitWidth
int lineWidth;
int lineHeight;
// apply weighting
int lineWidthFraction = 5;
if (weighting) {
double relativeThickness = 1 - e.getWeight() / getMaximumEdgeWeight();
lineWidth = Math.max((int) Math.round(unitWidth * relativeThickness / lineWidthFraction), 1);
lineHeight = Math.max((int) Math.round(unitHeight * relativeThickness / lineWidthFraction), 1);
// System.out.println("\t" + e + ", weight: " + e.getWeight() + ", e.getWeight() - getMinimumEdgeWeight(): "
// + (e.getWeight() - getMinimumEdgeWeight()) + " => relativeThickness: " + relativeThickness + " => " +
// lineWidth);
} else {
lineWidth = Math.round(unitWidth / lineWidthFraction);
lineHeight = Math.round(unitHeight / lineWidthFraction);
}
return new int[] { lineWidth, lineHeight };
}
/**
* @return Returns the maximum edge weight ({@link #maximumEdgeWeight})
*/
public double getMaximumEdgeWeight() {
return maximumEdgeWeight;
}
/**
* @return Returns the minimum edge weight ({@link #minimumEdgeWeight})
*/
public double getMinimumEdgeWeight() {
return minimumEdgeWeight;
}
}